This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 3a70962b7afe6e5078b0f1c4dc4c471ddc8cdce1 Author: Jiuzhu Dong <[email protected]> AuthorDate: Tue Jul 26 06:53:39 2022 +0000 fs/directory: use file mode to manage directory Signed-off-by: Jiuzhu Dong <[email protected]> --- arch/sim/src/sim/up_hostfs.c | 5 + fs/Makefile | 1 - fs/dirent/Make.defs | 26 - fs/dirent/fs_opendir.c | 306 ------------ fs/dirent/fs_readdir.c | 254 ---------- fs/dirent/fs_rewinddir.c | 140 ------ fs/dirent/fs_seekdir.c | 228 --------- fs/inode/inode.h | 10 + fs/littlefs/lfs_vfs.c | 7 - fs/unionfs/fs_unionfs.c | 2 - fs/vfs/Make.defs | 2 +- fs/vfs/fs_dir.c | 554 +++++++++++++++++++++ fs/vfs/fs_open.c | 45 +- include/dirent.h | 6 +- include/fcntl.h | 1 + include/nuttx/fs/dirent.h | 10 - include/nuttx/fs/fs.h | 7 - include/nuttx/fs/hostfs.h | 1 + libs/libc/dirent/Make.defs | 3 +- .../libc/dirent/lib_closedir.c | 95 +--- libs/libc/dirent/{lib_telldir.c => lib_opendir.c} | 56 ++- libs/libc/dirent/{lib_telldir.c => lib_readdir.c} | 44 +- .../libc/dirent/{lib_telldir.c => lib_rewinddir.c} | 36 +- libs/libc/dirent/{lib_telldir.c => lib_seekdir.c} | 38 +- libs/libc/dirent/lib_telldir.c | 19 +- 25 files changed, 699 insertions(+), 1197 deletions(-) diff --git a/arch/sim/src/sim/up_hostfs.c b/arch/sim/src/sim/up_hostfs.c index c3188c5946..607f04212c 100644 --- a/arch/sim/src/sim/up_hostfs.c +++ b/arch/sim/src/sim/up_hostfs.c @@ -186,6 +186,11 @@ int host_open(const char *pathname, int flags, nuttx_mode_t mode) mapflags |= O_CLOEXEC; } + if (flags & NUTTX_O_DIRECTORY) + { + mapflags |= O_DIRECTORY; + } + int ret = open(pathname, mapflags, mode); if (ret == -1) { diff --git a/fs/Makefile b/fs/Makefile index 4334eb967e..e3a1bd3794 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -25,7 +25,6 @@ CSRCS = fs_initialize.c include inode/Make.defs include vfs/Make.defs include driver/Make.defs -include dirent/Make.defs include aio/Make.defs include mmap/Make.defs diff --git a/fs/dirent/Make.defs b/fs/dirent/Make.defs deleted file mode 100644 index 53347b49ce..0000000000 --- a/fs/dirent/Make.defs +++ /dev/null @@ -1,26 +0,0 @@ -############################################################################ -# fs/dirent/Make.defs -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. The -# ASF licenses this file to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -############################################################################ - -CSRCS += fs_closedir.c fs_opendir.c fs_readdir.c fs_rewinddir.c fs_seekdir.c - -# Include dirent build support - -DEPPATH += --dep-path dirent -VPATH += :dirent diff --git a/fs/dirent/fs_opendir.c b/fs/dirent/fs_opendir.c deleted file mode 100644 index e41b46998f..0000000000 --- a/fs/dirent/fs_opendir.c +++ /dev/null @@ -1,306 +0,0 @@ -/**************************************************************************** - * fs/dirent/fs_opendir.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <stdbool.h> -#include <string.h> -#include <dirent.h> -#include <assert.h> -#include <errno.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> - -#include "inode/inode.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: open_mountpoint - * - * Description: - * Handle the case where the inode to be opened is within a mountpoint. - * - * Input Parameters: - * inode -- the inode of the mountpoint to open - * relpath -- the relative path within the mountpoint to open - * dir -- the dirent structure to be initialized - * - * Returned Value: - * On success, OK is returned; Otherwise, a positive errno is returned. - * - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_MOUNTPOINT -static inline int open_mountpoint(FAR struct inode *inode, - FAR const char *relpath, - FAR struct fs_dirent_s *dir) -{ - int ret; - - /* The inode itself as the 'root' of mounted volume. The actually - * directory is at relpath into the* mounted filesystem. - * - * Verify that the mountpoint inode supports the opendir() method - */ - - if (!inode->u.i_mops || !inode->u.i_mops->opendir) - { - return -ENOSYS; - } - - /* Perform the opendir() operation */ - - ret = inode->u.i_mops->opendir(inode, relpath, dir); - if (ret < 0) - { - /* Negate the error value so that it can be used to set errno */ - - return ret; - } - - return OK; -} -#endif - -/**************************************************************************** - * Name: open_pseudodir - * - * Description: - * Handle the case where the inode to be opened is within the top-level - * pseudo-file system. - * - * Input Parameters: - * inode -- the inode of the mountpoint to open - * dir -- the dirent structure to be initialized - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void open_pseudodir(FAR struct inode *inode, - FAR struct fs_dirent_s *dir) -{ - /* We have a valid pseudo-filesystem node. Take two references on the - * inode -- one for the parent (fd_root) and one for the child (fd_next). - */ - - inode_addref(inode); - - 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 */ - -#ifndef CONFIG_DISABLE_MOUNTPOINT - DIRENT_SETPSEUDONODE(dir->fd_flags); -#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. - * - * Input Parameters: - * dir -- the dirent structure to be initialized - * - * Returned Value: - * 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 kumm_zalloc */ - 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 - ****************************************************************************/ - -/**************************************************************************** - * Name: opendir - * - * Description: - * The opendir() function opens a directory stream corresponding to the - * directory name, and returns a pointer to the directory stream. The - * stream is positioned at the first entry in the directory. - * - * Input Parameters: - * path -- the directory to open - * - * Returned Value: - * The opendir() function returns a pointer to the directory stream. On - * error, NULL is returned, and errno is set appropriately. - * - * EACCES - Permission denied. - * EMFILE - Too many file descriptors in use by process. - * ENFILE - Too many files are currently open in the - * system. - * ENOENT - Directory does not exist, or name is an empty - * string. - * ENOMEM - Insufficient memory to complete the operation. - * ENOTDIR - 'path' is not a directory. - * - ****************************************************************************/ - -FAR DIR *opendir(FAR const char *path) -{ - FAR struct inode *inode = NULL; - FAR struct fs_dirent_s *dir; - struct inode_search_s desc; -#ifndef CONFIG_DISABLE_MOUNTPOINT - FAR const char *relpath = NULL; -#endif - int ret; - - /* If we are given 'nothing' then we will interpret this as - * request for the root inode. - */ - - SETUP_SEARCH(&desc, path, false); - - ret = inode_find(&desc); - if (ret < 0) - { - goto errout_with_search; - } - - /* Get the search results */ - -#ifndef CONFIG_DISABLE_MOUNTPOINT - relpath = desc.relpath; -#endif - - inode = desc.node; - DEBUGASSERT(inode != NULL); - - /* Allocate a type DIR -- which is little more than an inode - * container. - */ - - dir = (FAR struct fs_dirent_s *)kumm_zalloc(sizeof(struct fs_dirent_s)); - if (!dir) - { - /* Insufficient memory to complete the operation. */ - - ret = -ENOMEM; - goto errout_with_inode; - } - - /* 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 */ - - /* Is this a node in the pseudo filesystem? Or a mountpoint? */ - -#ifndef CONFIG_DISABLE_MOUNTPOINT - 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; - } - } - else -#endif - { - /* 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 != NULL) - { - /* 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; - } - } - - RELEASE_SEARCH(&desc); - return ((FAR DIR *)dir); - - /* Nasty goto's make error handling simpler */ - -errout_with_direntry: - kumm_free(dir); - -errout_with_inode: - inode_release(inode); - -errout_with_search: - RELEASE_SEARCH(&desc); - set_errno(-ret); - return NULL; -} diff --git a/fs/dirent/fs_readdir.c b/fs/dirent/fs_readdir.c deleted file mode 100644 index df6ef699ad..0000000000 --- a/fs/dirent/fs_readdir.c +++ /dev/null @@ -1,254 +0,0 @@ -/**************************************************************************** - * fs/dirent/fs_readdir.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <string.h> -#include <dirent.h> -#include <errno.h> - -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> - -#include "inode/inode.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: readpseudodir - ****************************************************************************/ - -static inline int readpseudodir(struct fs_dirent_s *idir) -{ - FAR struct inode *prev; - int ret; - - /* Check if we are at the end of the list */ - - if (!idir->u.pseudo.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 */ - - strlcpy(idir->fd_dir.d_name, idir->u.pseudo.fd_next->i_name, - sizeof(idir->fd_dir.d_name)); - - /* If the node has file operations, we will say that it is a file. */ - - idir->fd_dir.d_type = DTYPE_UNKNOWN; - if (idir->u.pseudo.fd_next->u.i_ops) - { -#ifndef CONFIG_DISABLE_MOUNTPOINT - if (INODE_IS_BLOCK(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_BLK; - } - else if (INODE_IS_MTD(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_MTD; - } - else if (INODE_IS_MOUNTPT(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_DIRECTORY; - } - else -#endif -#ifdef CONFIG_PSEUDOFS_SOFTLINKS - if (INODE_IS_SOFTLINK(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_LINK; - } - else -#endif - if (INODE_IS_DRIVER(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_CHR; - } - else if (INODE_IS_NAMEDSEM(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_SEM; - } - else if (INODE_IS_MQUEUE(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_MQ; - } - else if (INODE_IS_SHM(idir->u.pseudo.fd_next)) - { - idir->fd_dir.d_type = DTYPE_SHM; - } - } - - /* 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) - { - idir->fd_dir.d_type = DTYPE_DIRECTORY; - } - - /* Now get the inode to visit next time that readdir() is called */ - - ret = inode_semtake(); - if (ret < 0) - { - return ret; - } - - prev = idir->u.pseudo.fd_next; - idir->u.pseudo.fd_next = prev->i_peer; /* The next node to visit */ - - if (idir->u.pseudo.fd_next) - { - /* Increment the reference count on this next node */ - - idir->u.pseudo.fd_next->i_crefs++; - } - - inode_semgive(); - - if (prev) - { - inode_release(prev); - } - - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: readdir - * - * Description: - * The readdir() function returns a pointer to a dirent structure - * representing the next directory entry in the directory stream pointed - * to by dir. It returns NULL on reaching the end-of-file or if an error - * occurred. - * - * Input Parameters: - * dirp -- An instance of type DIR created by a previous call to opendir(); - * - * Returned Value: - * The readdir() function returns a pointer to a dirent structure, or NULL - * if an error occurs or end-of-file is reached. On error, errno is set - * appropriately. - * - * EBADF - Invalid directory stream descriptor dir - * - ****************************************************************************/ - -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; - } - - goto errout; - } - - /* Success */ - - idir->fd_position++; - return &idir->fd_dir; - -errout: - set_errno(-ret); - return NULL; -} diff --git a/fs/dirent/fs_rewinddir.c b/fs/dirent/fs_rewinddir.c deleted file mode 100644 index 14f427961f..0000000000 --- a/fs/dirent/fs_rewinddir.c +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** - * fs/dirent/fs_rewinddir.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <dirent.h> -#include <errno.h> - -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> - -#include "inode/inode.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: rewindpseudodir - ****************************************************************************/ - -static inline void rewindpseudodir(struct fs_dirent_s *idir) -{ - struct inode *prev; - int ret; - - ret = inode_semtake(); - if (ret < 0) - { - return; - } - - /* Reset the position to the beginning */ - - prev = idir->u.pseudo.fd_next; /* (Save to delete later) */ - idir->u.pseudo.fd_next = idir->fd_root; /* The next node to visit */ - idir->fd_position = 0; /* Reset position */ - - /* Increment the reference count on the root=next node. We - * should now have two references on the inode. - */ - - idir->fd_root->i_crefs++; - inode_semgive(); - - /* Then release the reference to the old next inode */ - - if (prev) - { - inode_release(prev); - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: rewinddir - * - * Description: - * The rewinddir() function resets the position of the - * directory stream dir to the beginning of the directory. - * - * Input Parameters: - * dirp -- An instance of type DIR created by a previous - * call to opendir(); - * - * Returned Value: - * None - * - ****************************************************************************/ - -void rewinddir(FAR DIR *dirp) -{ - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; -#ifndef CONFIG_DISABLE_MOUNTPOINT - struct inode *inode; -#endif - - /* 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 - 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); - } -} diff --git a/fs/dirent/fs_seekdir.c b/fs/dirent/fs_seekdir.c deleted file mode 100644 index ed8f24e3b3..0000000000 --- a/fs/dirent/fs_seekdir.c +++ /dev/null @@ -1,228 +0,0 @@ -/**************************************************************************** - * fs/dirent/fs_seekdir.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <sys/types.h> -#include <dirent.h> -#include <errno.h> -#include <debug.h> - -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> - -#include "inode/inode.h" - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: seekpseudodir - ****************************************************************************/ - -static inline void seekpseudodir(struct fs_dirent_s *idir, off_t offset) -{ - struct inode *curr; - struct inode *prev; - off_t pos; - int ret; - - /* Determine a starting point for the seek. If the seek - * is "forward" from the current position, then we will - * start at the current position. Otherwise, we will - * "rewind" to the root dir. - */ - - if (offset < idir->fd_position) - { - pos = 0; - curr = idir->fd_root; - } - else - { - pos = idir->fd_position; - curr = idir->u.pseudo.fd_next; - } - - /* Traverse the peer list starting at the 'root' of the - * the list until we find the node at 'offset". If devices - * are being registered and unregistered, then this can - * be a very unpredictable operation. - */ - - ret = inode_semtake(); - if (ret < 0) - { - ferr("ERROR: inode_semtake failed: %d\n", ret); - return; - } - - for (; curr && pos != offset; pos++, curr = curr->i_peer); - - /* Now get the inode to vist next time that readdir() is called */ - - prev = idir->u.pseudo.fd_next; - idir->u.pseudo.fd_next = curr; /* The next node to visit (might be null) */ - idir->fd_position = pos; /* Might be beyond the last dirent */ - - if (curr) - { - /* Increment the reference count on this next node */ - - curr->i_crefs++; - } - - inode_semgive(); - - if (prev) - { - inode_release(prev); - } -} - -/**************************************************************************** - * Name: seekmountptdir - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_MOUNTPOINT -static inline void seekmountptdir(struct fs_dirent_s *idir, off_t offset) -{ - struct inode *inode; - off_t pos; - - /* Determine a starting point for the seek. If the seek - * is "forward" from the current position, then we will - * start at the current position. Otherwise, we will - * "rewind" to the root dir. - */ - - inode = idir->fd_root; - if (offset < idir->fd_position) - { - if (inode->u.i_mops && inode->u.i_mops->rewinddir) - { - /* Perform the rewinddir() operation */ - - inode->u.i_mops->rewinddir(inode, idir); - pos = 0; - } - else - { - /* We can't do the seek and there is no way to return - * an error indication. - */ - - return; - } - } - else - { - pos = idir->fd_position; - } - - /* This is a brute force approach... we will just read - * directory entries until we are at the desired position. - */ - - while (pos < offset) - { - if (!inode->u.i_mops || !inode->u.i_mops->readdir || - inode->u.i_mops->readdir(inode, idir) < 0) - { - /* We can't read the next entry and there is no way to return - * an error indication. - */ - - return; - } - - /* Increment the position on each successful read */ - - pos++; - } - - /* If we get here the directory position has been successfully set */ - - idir->fd_position = pos; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: seekdir - * - * Description: - * The seekdir() function sets the location in the directory stream from - * which the next readdir() call will start. seekdir() should be used with - * an offset returned by telldir(). - * - * Input Parameters: - * dirp -- An instance of type DIR created by a previous - * call to opendir(); - * offset -- offset to seek to - * - * Returned Value: - * None - * - ****************************************************************************/ - -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); - } -} diff --git a/fs/inode/inode.h b/fs/inode/inode.h index e54652053a..53053107c3 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -419,6 +419,16 @@ int foreach_inode(foreach_inode_t handler, FAR void *arg); int files_allocate(FAR struct inode *inode, int oflags, off_t pos, FAR void *priv, int minfd); +/**************************************************************************** + * Name: dir_allocate + * + * Description: + * Allocate a directory instance and bind it to f_priv of filep. + * + ****************************************************************************/ + +int dir_allocate(FAR struct file *filep, FAR const char *relpath); + #undef EXTERN #if defined(__cplusplus) } diff --git a/fs/littlefs/lfs_vfs.c b/fs/littlefs/lfs_vfs.c index e84bc96801..003bdd3d37 100644 --- a/fs/littlefs/lfs_vfs.c +++ b/fs/littlefs/lfs_vfs.c @@ -767,8 +767,6 @@ static int littlefs_opendir(FAR struct inode *mountpt, goto errout; } - dir->fd_position = lfs_dir_tell(&fs->lfs, priv); - littlefs_semgive(fs); dir->u.littlefs = priv; return OK; @@ -845,7 +843,6 @@ static int littlefs_readdir(FAR struct inode *mountpt, ret = littlefs_convert_result(lfs_dir_read(&fs->lfs, priv, &info)); if (ret > 0) { - dir->fd_position = lfs_dir_tell(&fs->lfs, priv); if (info.type == LFS_TYPE_REG) { dir->fd_dir.d_type = DTYPE_FILE; @@ -894,10 +891,6 @@ static int littlefs_rewinddir(FAR struct inode *mountpt, } ret = littlefs_convert_result(lfs_dir_rewind(&fs->lfs, priv)); - if (ret >= 0) - { - dir->fd_position = lfs_dir_tell(&fs->lfs, priv); - } littlefs_semgive(fs); return ret; diff --git a/fs/unionfs/fs_unionfs.c b/fs/unionfs/fs_unionfs.c index 7c7ea37f54..49ef7da038 100644 --- a/fs/unionfs/fs_unionfs.c +++ b/fs/unionfs/fs_unionfs.c @@ -1920,7 +1920,6 @@ static int unionfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir) * application will see. */ - dir->fd_position = fu->fu_lower[fu->fu_ndx]->fd_position; memcpy(&dir->fd_dir, &fu->fu_lower[fu->fu_ndx]->fd_dir, sizeof(struct dirent)); } @@ -1976,7 +1975,6 @@ static int unionfs_rewinddir(struct inode *mountpt, struct fs_dirent_s *dir) if (ops->rewinddir != NULL) { ret = ops->rewinddir(um->um_node, fu->fu_lower[fu->fu_ndx]); - dir->fd_position = fu->fu_lower[fu->fu_ndx]->fd_position; } } diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 61455c1080..1efdd4216b 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -24,7 +24,7 @@ CSRCS += fs_chstat.c fs_close.c fs_dup.c fs_dup2.c fs_fcntl.c fs_epoll.c CSRCS += fs_fchstat.c fs_fstat.c fs_fstatfs.c fs_ioctl.c fs_lseek.c CSRCS += fs_mkdir.c fs_open.c fs_poll.c fs_pread.c fs_pwrite.c fs_read.c CSRCS += fs_rename.c fs_rmdir.c fs_select.c fs_sendfile.c fs_stat.c -CSRCS += fs_statfs.c fs_unlink.c fs_write.c +CSRCS += fs_statfs.c fs_unlink.c fs_write.c fs_dir.c # Certain interfaces are not available if there is no mountpoint support diff --git a/fs/vfs/fs_dir.c b/fs/vfs/fs_dir.c new file mode 100644 index 0000000000..0c698acd77 --- /dev/null +++ b/fs/vfs/fs_dir.c @@ -0,0 +1,554 @@ +/**************************************************************************** + * fs/vfs/fs_dir.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <string.h> +#include <errno.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/fs/fs.h> +#include <nuttx/fs/dirent.h> + +#include "inode/inode.h" + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static int dir_close(FAR struct file *filep); +static ssize_t dir_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static off_t dir_seek(FAR struct file *filep, off_t offset, int whence); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_dir_fileops = +{ + NULL, /* open */ + dir_close, /* close */ + dir_read, /* read */ + NULL, /* write */ + dir_seek, /* seek */ + NULL, /* ioctl */ + NULL, /* poll */ +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + NULL, /* unlink */ +#endif +}; + +static struct inode g_dir_inode = +{ + NULL, + NULL, + NULL, + 1, + 0, + { &g_dir_fileops }, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: open_mountpoint + * + * Description: + * Handle the case where the inode to be opened is within a mountpoint. + * + * Input Parameters: + * inode -- the inode of the mountpoint to open + * relpath -- the relative path within the mountpoint to open + * dir -- the dirent structure to be initialized + * + * Returned Value: + * On success, 0 is returned; Otherwise, a negative errno is returned. + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static int open_mountpoint(FAR struct inode *inode, FAR const char *relpath, + FAR struct fs_dirent_s *dir) +{ + /* The inode itself as the 'root' of mounted volume. The actually + * directory is at relpath into the mounted filesystem. + * + * Verify that the mountpoint inode supports the opendir() method. + */ + + if (inode->u.i_mops == NULL || inode->u.i_mops->opendir == NULL || + inode->u.i_mops->readdir == NULL) + { + return -ENOSYS; + } + + dir->fd_root = inode; + + return inode->u.i_mops->opendir(inode, relpath, dir); +} +#endif + +/**************************************************************************** + * Name: open_pseudodir + * + * Description: + * Handle the case where the inode to be opened is within the top-level + * pseudo-file system. + * + * Input Parameters: + * inode -- the inode of the mountpoint to open + * dir -- the dirent structure to be initialized + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void open_pseudodir(FAR struct inode *inode, + FAR struct fs_dirent_s *dir) +{ + dir->fd_root = inode; /* Save the inode where we start */ + dir->u.pseudo.fd_next = inode->i_child; /* The next node for readdir */ + inode_addref(inode->i_child); +} + +/**************************************************************************** + * Name: seek_pseudodir + ****************************************************************************/ + +static off_t seek_pseudodir(FAR struct file *filep, off_t offset) +{ + FAR struct fs_dirent_s *dir = filep->f_priv; + FAR struct inode *curr; + FAR struct inode *prev; + off_t pos; + + /* Determine a starting point for the seek. If the seek + * is "forward" from the current position, then we will + * start at the current position. Otherwise, we will + * "rewind" to the root dir. + */ + + if (offset < filep->f_pos) + { + pos = 0; + curr = dir->fd_root->i_child; + } + else + { + pos = filep->f_pos; + curr = dir->u.pseudo.fd_next; + } + + /* Traverse the peer list starting at the 'root' of the + * the list until we find the node at 'offset". If devices + * are being registered and unregistered, then this can + * be a very unpredictable operation. + */ + + inode_semtake(); + + for (; curr != NULL && pos != offset; pos++, curr = curr->i_peer); + + /* Now get the inode to vist next time that readdir() is called */ + + prev = dir->u.pseudo.fd_next; + + /* The next node to visit (might be null) */ + + dir->u.pseudo.fd_next = curr; + if (curr != NULL) + { + /* Increment the reference count on this next node */ + + curr->i_crefs++; + } + + inode_semgive(); + + if (prev != NULL) + { + inode_release(prev); + } + + return pos; +} + +/**************************************************************************** + * Name: seek_mountptdir + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_MOUNTPOINT +static off_t seek_mountptdir(FAR struct file *filep, off_t offset) +{ + FAR struct fs_dirent_s *dir = filep->f_priv; + FAR struct inode *inode = dir->fd_root; + off_t pos; + + /* Determine a starting point for the seek. If the seek + * is "forward" from the current position, then we will + * start at the current position. Otherwise, we will + * "rewind" to the root dir. + */ + + if (offset < filep->f_pos) + { + if (inode->u.i_mops->rewinddir != NULL) + { + inode->u.i_mops->rewinddir(inode, dir); + pos = 0; + } + else + { + return -ENOTSUP; + } + } + else + { + pos = filep->f_pos; + } + + /* This is a brute force approach... we will just read + * directory entries until we are at the desired position. + */ + + while (pos < offset) + { + int ret; + + ret = inode->u.i_mops->readdir(inode, dir); + if (ret < 0) + { + return ret; + } + + /* Increment the position on each successful read */ + + pos++; + } + + return pos; +} +#endif + +/**************************************************************************** + * Name: read_pseudodir + ****************************************************************************/ + +static int read_pseudodir(FAR struct fs_dirent_s *dir) +{ + FAR struct inode *prev; + + /* Check if we are at the end of the list */ + + if (dir->u.pseudo.fd_next == NULL) + { + /* 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 */ + + strlcpy(dir->fd_dir.d_name, dir->u.pseudo.fd_next->i_name, + sizeof(dir->fd_dir.d_name)); + + /* If the node has file operations, we will say that it is a file. */ + + dir->fd_dir.d_type = DTYPE_UNKNOWN; + if (dir->u.pseudo.fd_next->u.i_ops != NULL) + { +#ifndef CONFIG_DISABLE_MOUNTPOINT + if (INODE_IS_BLOCK(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_BLK; + } + else if (INODE_IS_MTD(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_MTD; + } + else if (INODE_IS_MOUNTPT(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_DIRECTORY; + } + else +#endif +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + if (INODE_IS_SOFTLINK(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_LINK; + } + else +#endif + if (INODE_IS_DRIVER(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_CHR; + } + else if (INODE_IS_NAMEDSEM(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_SEM; + } + else if (INODE_IS_MQUEUE(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_MQ; + } + else if (INODE_IS_SHM(dir->u.pseudo.fd_next)) + { + dir->fd_dir.d_type = DTYPE_SHM; + } + } + + /* 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 (dir->u.pseudo.fd_next->i_child != NULL || + dir->u.pseudo.fd_next->u.i_ops == NULL) + { + dir->fd_dir.d_type = DTYPE_DIRECTORY; + } + + /* Now get the inode to visit next time that readdir() is called */ + + inode_semtake(); + + prev = dir->u.pseudo.fd_next; + dir->u.pseudo.fd_next = prev->i_peer; /* The next node to visit */ + + if (dir->u.pseudo.fd_next != NULL) + { + /* Increment the reference count on this next node */ + + dir->u.pseudo.fd_next->i_crefs++; + } + + inode_semgive(); + + if (prev != NULL) + { + inode_release(prev); + } + + return 0; +} + +static int dir_close(FAR struct file *filep) +{ + FAR struct fs_dirent_s *dir = filep->f_priv; + FAR struct inode *inode = dir->fd_root; + int ret = 0; + + /* This is the 'root' inode of the directory. This means different + * things with different filesystems. + */ + +#ifndef CONFIG_DISABLE_MOUNTPOINT + /* The way that we handle the close operation depends on what kind of + * root inode we have open. + */ + + if (INODE_IS_MOUNTPT(inode)) + { + /* The node is a file system mointpoint. Verify that the + * mountpoint supports the closedir() method (not an error if it + * does not) + */ + + if (inode->u.i_mops->closedir != NULL) + { + ret = inode->u.i_mops->closedir(inode, dir); + } + } + else +#endif + { + /* The node is part of the root pseudo file system, release + * our contained reference to the 'next' inode. + */ + + if (dir->u.pseudo.fd_next != NULL) + { + inode_release(dir->u.pseudo.fd_next); + } + + /* Then release the container */ + + kmm_free(dir); + } + + /* Release our references on the contained 'root' inode */ + + inode_release(inode); + return ret; +} + +static ssize_t dir_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct fs_dirent_s *dir = filep->f_priv; +#ifndef CONFIG_DISABLE_MOUNTPOINT + FAR struct inode *inode = dir->fd_root; +#endif + int ret; + + /* Verify that we were provided with a valid directory structure */ + + if (buffer == NULL || buflen < sizeof(struct dirent)) + { + return -EINVAL; + } + + /* 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)) + { + ret = inode->u.i_mops->readdir(inode, dir); + } + else +#endif + { + /* The node is part of the root pseudo file system */ + + ret = read_pseudodir(dir); + } + + /* ret < 0 is an error. Special case: ret = -ENOENT is end of file */ + + if (ret < 0) + { + if (ret == -ENOENT) + { + ret = 0; + } + + return ret; + } + + filep->f_pos++; + memcpy(buffer, &dir->fd_dir, sizeof(dir->fd_dir)); + return sizeof(dir->fd_dir); +} + +static off_t dir_seek(FAR struct file *filep, off_t offset, int whence) +{ + off_t pos = 0; + + /* The way we handle the readdir depends on the type of inode + * that we are dealing with. + */ + + if (whence == SEEK_SET) + { +#ifndef CONFIG_DISABLE_MOUNTPOINT + FAR struct fs_dirent_s *dir = filep->f_priv; + + if (INODE_IS_MOUNTPT(dir->fd_root)) + { + pos = seek_mountptdir(filep, offset); + } + else +#endif + { + pos = seek_pseudodir(filep, offset); + } + } + else if (whence == SEEK_CUR) + { + return filep->f_pos; + } + else + { + return -EINVAL; + } + + if (pos >= 0) + { + filep->f_pos = pos; + } + + return pos; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: dir_allocate + * + * Description: + * Allocate a directory instance and bind it to f_priv of filep. + * + ****************************************************************************/ + +int dir_allocate(FAR struct file *filep, FAR const char *relpath) +{ + FAR struct fs_dirent_s *dir; + FAR struct inode *inode = filep->f_inode; + int ret = 0; + + dir = kmm_zalloc(sizeof(struct fs_dirent_s)); + if (dir == NULL) + { + return -ENOMEM; + } + + /* Is this a node in the pseudo filesystem? Or a mountpoint? */ + +#ifndef CONFIG_DISABLE_MOUNTPOINT + if (INODE_IS_MOUNTPT(inode)) + { + /* Open the directory at the relative path */ + + ret = open_mountpoint(inode, relpath, dir); + if (ret < 0) + { + goto errout_with_direntry; + } + } + else +#endif + { + open_pseudodir(inode, dir); + } + + filep->f_inode = &g_dir_inode; + filep->f_priv = dir; + inode_addref(&g_dir_inode); + + return ret; + +errout_with_direntry: + kmm_free(dir); + return ret; +} diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index b7fd56b17d..85ca1fa5a6 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -116,25 +116,8 @@ static int file_vopen(FAR struct file *filep, FAR const char *path, return block_proxy(filep, path, oflags); } - 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); @@ -155,20 +138,30 @@ static int file_vopen(FAR struct file *filep, FAR const char *path, * because it may also be closed that many times. */ - ret = OK; - if (inode->u.i_ops->open) + if (oflags & O_DIRECTORY) { + ret = dir_allocate(filep, desc.relpath); + } #ifndef CONFIG_DISABLE_MOUNTPOINT - if (INODE_IS_MOUNTPT(inode)) + else if (INODE_IS_MOUNTPT(inode)) + { + if (inode->u.i_mops->open != NULL) { ret = inode->u.i_mops->open(filep, desc.relpath, oflags, mode); } - else + } #endif + else if (INODE_IS_DRIVER(inode)) + { + if (inode->u.i_ops->open != NULL) { ret = inode->u.i_ops->open(filep); } } + else + { + ret = -ENXIO; + } if (ret < 0) { @@ -232,6 +225,16 @@ static int nx_vopen(FAR const char *path, int oflags, va_list ap) int inode_checkflags(FAR struct inode *inode, int oflags) { + if (INODE_IS_PSEUDODIR(inode)) + { + return OK; + } + + if (inode->u.i_ops == NULL) + { + return -ENXIO; + } + if (((oflags & O_RDOK) != 0 && !inode->u.i_ops->read) || ((oflags & O_WROK) != 0 && !inode->u.i_ops->write)) { diff --git a/include/dirent.h b/include/dirent.h index 7a1ed7180f..8865059f63 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -114,7 +114,11 @@ struct dirent char d_name[NAME_MAX + 1]; /* File name */ }; -typedef void DIR; +typedef struct +{ + int fd; + struct dirent entry; +} DIR; /**************************************************************************** * Public Data diff --git a/include/fcntl.h b/include/fcntl.h index 77f678126f..25a0cce335 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -52,6 +52,7 @@ #define O_TEXT (1 << 8) /* Open the file in text (translated) mode. */ #define O_DIRECT (1 << 9) /* Avoid caching, write directly to hardware */ #define O_CLOEXEC (1 << 10) /* Close on execute */ +#define O_DIRECTORY (1 << 11) /* Must be a directory */ /* Unsupported, but required open flags */ diff --git a/include/nuttx/fs/dirent.h b/include/nuttx/fs/dirent.h index 29217e373d..d66a8bc24f 100644 --- a/include/nuttx/fs/dirent.h +++ b/include/nuttx/fs/dirent.h @@ -259,16 +259,6 @@ struct fs_dirent_s struct inode *fd_root; - /* At present, only mountpoints require special handling flags */ - -#ifndef CONFIG_DISABLE_MOUNTPOINT - unsigned int fd_flags; -#endif - - /* This keeps track of the current directory position for telldir */ - - off_t fd_position; - /* Retained control information depends on the type of file system that * provides the mountpoint. Ideally this information should * be hidden behind an opaque, file-system-dependent void *, but we put diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index f883b4f7bc..e8baeba1ee 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -148,13 +148,6 @@ #define INODE_SET_SOFTLINK(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) #define INODE_SET_SOCKET(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOCKET) -/* Mountpoint fd_flags values */ - -#define DIRENTFLAGS_PSEUDONODE 1 - -#define DIRENT_SETPSEUDONODE(f) do (f) |= DIRENTFLAGS_PSEUDONODE; while (0) -#define DIRENT_ISPSEUDONODE(f) (((f) & DIRENTFLAGS_PSEUDONODE) != 0) - /* The status change flags. * These should be or-ed together to figure out what want to change. */ diff --git a/include/nuttx/fs/hostfs.h b/include/nuttx/fs/hostfs.h index 6773512ef4..85cd7cdcb6 100644 --- a/include/nuttx/fs/hostfs.h +++ b/include/nuttx/fs/hostfs.h @@ -85,6 +85,7 @@ #define NUTTX_O_BINARY (1 << 8) /* Open the file in binary mode. */ #define NUTTX_O_DIRECT (1 << 9) /* Avoid caching, write directly to hardware */ #define NUTTX_O_CLOEXEC (1 << 10) /* Close on execute */ +#define NUTTX_O_DIRECTORY (1 << 11) /* Must be a directory */ #define NUTTX_O_RDWR (NUTTX_O_RDONLY | NUTTX_O_WRONLY) diff --git a/libs/libc/dirent/Make.defs b/libs/libc/dirent/Make.defs index eabdc5942b..f8690bea4a 100644 --- a/libs/libc/dirent/Make.defs +++ b/libs/libc/dirent/Make.defs @@ -21,7 +21,8 @@ # Add the dirent C files to the build CSRCS += lib_readdirr.c lib_telldir.c lib_alphasort.c lib_scandir.c -CSRCS += lib_ftw.c lib_nftw.c +CSRCS += lib_ftw.c lib_nftw.c lib_opendir.c lib_closedir.c lib_readdir.c +CSRCS += lib_rewinddir.c lib_seekdir.c # Add the dirent directory to the build diff --git a/fs/dirent/fs_closedir.c b/libs/libc/dirent/lib_closedir.c similarity index 50% rename from fs/dirent/fs_closedir.c rename to libs/libc/dirent/lib_closedir.c index bd659ccfe9..e547dc9ad8 100644 --- a/fs/dirent/fs_closedir.c +++ b/libs/libc/dirent/lib_closedir.c @@ -1,5 +1,5 @@ /**************************************************************************** - * fs/dirent/fs_closedir.c + * libs/libc/dirent/lib_closedir.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -22,16 +22,11 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> - #include <dirent.h> #include <errno.h> +#include <unistd.h> -#include <nuttx/kmalloc.h> -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> - -#include "inode/inode.h" +#include "libc.h" /**************************************************************************** * Private Functions @@ -60,87 +55,15 @@ int closedir(FAR DIR *dirp) { - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; -#ifndef CONFIG_DISABLE_MOUNTPOINT - struct inode *inode; -#endif int ret; - /* Verify that we were provided with a valid directory structure */ - - if (!idir) + if (dirp == NULL) { - 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 childre. - */ - - if (idir->fd_root) - { - /* This is the 'root' inode of the directory. This means different - * things with different filesystems. - */ - -#ifndef CONFIG_DISABLE_MOUNTPOINT - 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) - */ - - if (inode->u.i_mops && inode->u.i_mops->closedir) - { - /* Perform the closedir() operation */ - - ret = inode->u.i_mops->closedir(inode, idir); - if (ret < 0) - { - goto errout_with_inode; - } - } - } - 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); - } - } - - /* Release our references on the contained 'root' inode */ - - inode_release(idir->fd_root); + set_errno(EBADF); + return -1; } - /* Then release the container */ - - kumm_free(idir); - return OK; - -#ifndef CONFIG_DISABLE_MOUNTPOINT -errout_with_inode: - inode_release(inode); - kumm_free(idir); -#endif - -errout: - set_errno(-ret); - return ERROR; + ret = close(dirp->fd); + lib_free(dirp); + return ret; } diff --git a/libs/libc/dirent/lib_telldir.c b/libs/libc/dirent/lib_opendir.c similarity index 60% copy from libs/libc/dirent/lib_telldir.c copy to libs/libc/dirent/lib_opendir.c index dcf61b56f0..aba6953277 100644 --- a/libs/libc/dirent/lib_telldir.c +++ b/libs/libc/dirent/lib_opendir.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libs/libc/dirent/lib_telldir.c + * libs/libc/dirent/lib_opendir.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -22,14 +22,12 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> - -#include <sys/types.h> #include <dirent.h> #include <errno.h> +#include <fcntl.h> +#include <string.h> -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> +#include "libc.h" /**************************************************************************** * Private Functions @@ -40,36 +38,50 @@ ****************************************************************************/ /**************************************************************************** - * Name: telldir + * Name: opendir * * Description: - * The telldir() function returns the current location - * associated with the directory stream dirp. + * The opendir() function opens a directory stream corresponding to the + * directory name, and returns a pointer to the directory stream. The + * stream is positioned at the first entry in the directory. * * Input Parameters: - * dirp -- An instance of type DIR created by a previous - * call to opendir(); + * path -- the directory to open * * Returned Value: - * On success, the telldir() function returns the current - * location in the directory stream. On error, -1 is - * returned, and errno is set appropriately. + * The opendir() function returns a pointer to the directory stream. On + * error, NULL is returned, and errno is set appropriately. * - * EBADF - Invalid directory stream descriptor dir + * EACCES - Permission denied. + * EMFILE - Too many file descriptors in use by process. + * ENFILE - Too many files are currently open in the + * system. + * ENOENT - Directory does not exist, or name is an empty + * string. + * ENOMEM - Insufficient memory to complete the operation. + * ENOTDIR - 'path' is not a directory. * ****************************************************************************/ -off_t telldir(FAR DIR *dirp) +FAR DIR *opendir(FAR const char *path) { - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; + FAR DIR *dir; + int fd; - if (!idir || !idir->fd_root) + dir = lib_malloc(sizeof(*dir)); + if (dir == NULL) { - set_errno(EBADF); - return (off_t)-1; + set_errno(ENOMEM); + return NULL; } - /* Just return the current position */ + fd = open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC); + if (fd < 0) + { + lib_free(dir); + return NULL; + } - return idir->fd_position; + dir->fd = fd; + return dir; } diff --git a/libs/libc/dirent/lib_telldir.c b/libs/libc/dirent/lib_readdir.c similarity index 68% copy from libs/libc/dirent/lib_telldir.c copy to libs/libc/dirent/lib_readdir.c index dcf61b56f0..5438463ec9 100644 --- a/libs/libc/dirent/lib_telldir.c +++ b/libs/libc/dirent/lib_readdir.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libs/libc/dirent/lib_telldir.c + * libs/libc/dirent/lib_readdir.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -22,14 +22,9 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> - -#include <sys/types.h> #include <dirent.h> #include <errno.h> - -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> +#include <unistd.h> /**************************************************************************** * Private Functions @@ -40,36 +35,41 @@ ****************************************************************************/ /**************************************************************************** - * Name: telldir + * Name: readdir * * Description: - * The telldir() function returns the current location - * associated with the directory stream dirp. + * The readdir() function returns a pointer to a dirent structure + * representing the next directory entry in the directory stream pointed + * to by dir. It returns NULL on reaching the end-of-file or if an error + * occurred. * * Input Parameters: - * dirp -- An instance of type DIR created by a previous - * call to opendir(); + * dirp -- An instance of type DIR created by a previous call to opendir(); * * Returned Value: - * On success, the telldir() function returns the current - * location in the directory stream. On error, -1 is - * returned, and errno is set appropriately. + * The readdir() function returns a pointer to a dirent structure, or NULL + * if an error occurs or end-of-file is reached. On error, errno is set + * appropriately. * - * EBADF - Invalid directory stream descriptor dir + * EBADF - Invalid directory stream descriptor dir * ****************************************************************************/ -off_t telldir(FAR DIR *dirp) +FAR struct dirent *readdir(DIR *dirp) { - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; + int ret; - if (!idir || !idir->fd_root) + if (!dirp) { set_errno(EBADF); - return (off_t)-1; + return NULL; } - /* Just return the current position */ + ret = read(dirp->fd, &dirp->entry, sizeof(struct dirent)); + if (ret <= 0) + { + return NULL; + } - return idir->fd_position; + return &dirp->entry; } diff --git a/libs/libc/dirent/lib_telldir.c b/libs/libc/dirent/lib_rewinddir.c similarity index 73% copy from libs/libc/dirent/lib_telldir.c copy to libs/libc/dirent/lib_rewinddir.c index dcf61b56f0..b181c98546 100644 --- a/libs/libc/dirent/lib_telldir.c +++ b/libs/libc/dirent/lib_rewinddir.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libs/libc/dirent/lib_telldir.c + * libs/libc/dirent/lib_rewinddir.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -22,14 +22,9 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> - -#include <sys/types.h> #include <dirent.h> #include <errno.h> - -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> +#include <unistd.h> /**************************************************************************** * Private Functions @@ -40,36 +35,29 @@ ****************************************************************************/ /**************************************************************************** - * Name: telldir + * Name: rewinddir * * Description: - * The telldir() function returns the current location - * associated with the directory stream dirp. + * The rewinddir() function resets the position of the + * directory stream dir to the beginning of the directory. * * Input Parameters: * dirp -- An instance of type DIR created by a previous * call to opendir(); * * Returned Value: - * On success, the telldir() function returns the current - * location in the directory stream. On error, -1 is - * returned, and errno is set appropriately. - * - * EBADF - Invalid directory stream descriptor dir + * None * ****************************************************************************/ -off_t telldir(FAR DIR *dirp) +void rewinddir(FAR DIR *dirp) { - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; - - if (!idir || !idir->fd_root) + if (dirp != NULL) + { + lseek(dirp->fd, 0, SEEK_SET); + } + else { set_errno(EBADF); - return (off_t)-1; } - - /* Just return the current position */ - - return idir->fd_position; } diff --git a/libs/libc/dirent/lib_telldir.c b/libs/libc/dirent/lib_seekdir.c similarity index 73% copy from libs/libc/dirent/lib_telldir.c copy to libs/libc/dirent/lib_seekdir.c index dcf61b56f0..28b7ac2d2c 100644 --- a/libs/libc/dirent/lib_telldir.c +++ b/libs/libc/dirent/lib_seekdir.c @@ -1,5 +1,5 @@ /**************************************************************************** - * libs/libc/dirent/lib_telldir.c + * libs/libc/dirent/lib_seekdir.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -22,14 +22,9 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> - -#include <sys/types.h> #include <dirent.h> #include <errno.h> - -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> +#include <unistd.h> /**************************************************************************** * Private Functions @@ -40,36 +35,31 @@ ****************************************************************************/ /**************************************************************************** - * Name: telldir + * Name: seekdir * * Description: - * The telldir() function returns the current location - * associated with the directory stream dirp. + * The seekdir() function sets the location in the directory stream from + * which the next readdir() call will start. seekdir() should be used with + * an offset returned by telldir(). * * Input Parameters: * dirp -- An instance of type DIR created by a previous * call to opendir(); + * offset -- offset to seek to * * Returned Value: - * On success, the telldir() function returns the current - * location in the directory stream. On error, -1 is - * returned, and errno is set appropriately. - * - * EBADF - Invalid directory stream descriptor dir + * None * ****************************************************************************/ -off_t telldir(FAR DIR *dirp) +void seekdir(FAR DIR *dirp, off_t offset) { - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; - - if (!idir || !idir->fd_root) + if (dirp != NULL) + { + lseek(dirp->fd, offset, SEEK_SET); + } + else { set_errno(EBADF); - return (off_t)-1; } - - /* Just return the current position */ - - return idir->fd_position; } diff --git a/libs/libc/dirent/lib_telldir.c b/libs/libc/dirent/lib_telldir.c index dcf61b56f0..e3739ee4c5 100644 --- a/libs/libc/dirent/lib_telldir.c +++ b/libs/libc/dirent/lib_telldir.c @@ -22,15 +22,10 @@ * Included Files ****************************************************************************/ -#include <nuttx/config.h> - -#include <sys/types.h> #include <dirent.h> +#include <unistd.h> #include <errno.h> -#include <nuttx/fs/fs.h> -#include <nuttx/fs/dirent.h> - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -61,15 +56,11 @@ off_t telldir(FAR DIR *dirp) { - struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp; - - if (!idir || !idir->fd_root) + if (dirp != NULL) { - set_errno(EBADF); - return (off_t)-1; + return lseek(dirp->fd, 0, SEEK_CUR); } - /* Just return the current position */ - - return idir->fd_position; + set_errno(EBADF); + return -1; }
