diff --git a/nuttx/fs/Makefile b/nuttx/fs/Makefile index 69ffce62d..468e4e803 100644 --- a/nuttx/fs/Makefile +++ b/nuttx/fs/Makefile @@ -43,7 +43,7 @@ AOBJS = $(ASRCS:.S=$(OBJEXT)) CSRCS = fs_open.c fs_close.c fs_read.c fs_write.c fs_ioctl.c fs_dup.c \ fs_opendir.c fs_closedir.c fs_readdir.c fs_readdirr.c \ fs_seekdir.c fs_telldir.c fs_rewinddir.c fs_fsync.c fs_files.c \ - fs_inode.c fs_inodefind.c fs_inodefinddir.c fs_inodereserve.c \ + fs_inode.c fs_inodefind.c fs_inodereserve.c \ fs_inoderemove.c fs_registerdriver.c fs_unregisterdriver.c \ fs_registerblockdriver.c fs_unregisterblockdriver.c \ fs_mount.c fs_umount.c fs_unlink.c fs_mkdir.c fs_rmdir.c \ diff --git a/nuttx/fs/fs_closedir.c b/nuttx/fs/fs_closedir.c index fd2d79d05..a8104b4d2 100644 --- a/nuttx/fs/fs_closedir.c +++ b/nuttx/fs/fs_closedir.c @@ -77,24 +77,43 @@ int closedir(FAR DIR *dirp) { struct internal_dir_s *idir = (struct internal_dir_s *)dirp; - if (!idir) + if (!idir || !idir->root) { *get_errno_ptr() = EBADF; return ERROR; } - /* Release our references on the contained inodes */ + /* The way that we handle the close operation depends on what kind of root + * inode we have open. + */ + + if (IS_MOUNTPT_INODE(idir->root)) + { + /* The node is a file system mointpoint */ + +#warning "Mountpoint support not implemented" + *get_errno_ptr() = ENOSYS; + return ERROR; + } + else + { + /* The node is part of the root psuedo file system, release + * our contained reference to the 'next' inode. + */ + + if (idir->u.psuedo.next) + { + inode_release(idir->u.psuedo.next); + } + } + + /* Release our references on the contained 'root' inode */ if (idir->root) { inode_release(idir->root); } - if (idir->next) - { - inode_release(idir->next); - } - /* Then release the container */ free(idir); diff --git a/nuttx/fs/fs_inodefinddir.c b/nuttx/fs/fs_inodefinddir.c deleted file mode 100644 index dcd6f4f30..000000000 --- a/nuttx/fs/fs_inodefinddir.c +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************ - * fs_inodefinddir.c - * - * Copyright (C) 2007 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name Gregory Nutt nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************/ - -/************************************************************ - * Included Files - ************************************************************/ - -#include -#include -#include -#include -#include -#include "fs_internal.h" - -#if CONFIG_NFILE_DESCRIPTORS >0 - -/************************************************************ - * Definitions - ************************************************************/ - -/************************************************************ - * Private Variables - ************************************************************/ - -/************************************************************ - * Public Variables - ************************************************************/ - -/************************************************************ - * Private Functions - ************************************************************/ - -/************************************************************ - * Public Functions - ************************************************************/ - -/************************************************************ - * Name: inode_finddir - * - * Description: - * This is called from the opendir() logic to get a reference - * to the inode associated with a directory. There are no - * real directories in this design; For our purposes, a - * directory inode is simply one that has children. - * - ************************************************************/ - -FAR struct inode *inode_finddir(const char *path) -{ - FAR struct inode *node; - FAR struct inode *child = NULL; - - /* If we are given 'nothing' then we will interpret this as - * request for the root inode. - */ - - if (!path || *path == 0 || strcmp(path, "/") == 0) - { - return root_inode; - } - - /* We don't know what to do with relative pathes */ - - if (*path != '/') - { - return NULL; - } - - /* Find the node matching the path. */ - - inode_semtake(); - - /* Handle some special cases */ - - node = inode_search(&path, (FAR void*)NULL, (FAR void*)NULL, (FAR const char**)NULL); - if (node) - { - /* Does the inode have a child? If so that the child - * would be the 'head' of a list of nodes under the - * directory. - */ - - child = node->i_child; - if (child) - { - /* If found, then increment the count of - * references on the child node. - */ - - child->i_crefs++; - } - } - inode_semgive(); - return child; -} - -#endif /* CONFIG_NFILE_DESCRIPTORS */ diff --git a/nuttx/fs/fs_internal.h b/nuttx/fs/fs_internal.h index 2912ff2b7..c20ab2176 100644 --- a/nuttx/fs/fs_internal.h +++ b/nuttx/fs/fs_internal.h @@ -79,12 +79,56 @@ struct internal_dir_s { - struct inode *root; /* The start inode (in case we - * rewind) */ - struct inode *next; /* The inode to use for the next call - * to readdir() */ - struct dirent dir; /* Populated using inode when readdir - * is called */ + /* This is the node that was opened by opendir. The type of the inode + * determines the way that the readdir() operations are performed. For the + * psuedo root psuedo-file system, it is also used to support rewind. + * + * We hold a reference on this inode so we know that it will persist until + * closedir() is called (although inodes linked to this inode may change). + */ + + struct inode *root; + + /* This keeps track of the current directory position for telldir */ + + off_t position; + + /* Retained control information depends on the type of file system that + * provides is provides the mountpoint. Ideally this information should + * be hidden behind an opaque, file-system-dependent void *, but we put + * the private definitions in line here for now to reduce allocations. + */ + + union + { + /* For the root psuedo-file system, we need retain only the 'next' inode + * need for the next readdir() operation. We hold a reference on this + * inode so we know that it will persist until closedir is called. + */ + + struct + { + struct inode *next; /* The inode for the next call to readdir() */ + } psuedo; + +#ifdef CONFIG_FS_FAT + /* For fat, we need to retun the start cluster, current cluster, current + * sector and current directory index. + */ + + struct + { + uint32 startcluster; /* Starting cluster of directory */ + uint32 currcluster; /* The current cluster being read */ + size_t currsector; /* The current sector being read */ + unsigned int dirindex; /* The next directory entry to read */ + } fat; +#endif + } u; + + /* In any event, this the actual struct dirent that is returned by readdir */ + + struct dirent dir; /* Populated when readdir is called */ }; /**************************************************************************** @@ -128,10 +172,6 @@ EXTERN STATUS inode_remove(const char *path); EXTERN FAR struct inode *inode_find(const char *path, const char **relpath); -/* fs_inodefinddir.c *********************************************************/ - -EXTERN FAR struct inode *inode_finddir(const char *path); - /* fs_inodeaddref.c **********************************************************/ EXTERN void inode_addref(FAR struct inode *inode); diff --git a/nuttx/fs/fs_opendir.c b/nuttx/fs/fs_opendir.c index b02d97bf7..24462d53b 100644 --- a/nuttx/fs/fs_opendir.c +++ b/nuttx/fs/fs_opendir.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include "fs_internal.h" @@ -49,6 +50,92 @@ * Private Functions ************************************************************/ +/************************************************************ + * Name: fs_finddirnode + * + * Description: + * This is called from the opendir() logic to get a reference + * to the inode associated with a directory. There are no + * real directories in this design; For our purposes, a + * directory inode is simply one that has children or one + * that is a mountpoint for a "real" file system + * + ************************************************************/ + +static inline FAR struct inode *fs_finddirnode(const char *path, const char **relpath) +{ + FAR struct inode *node; + FAR struct inode *root = NULL; + + /* If we are given 'nothing' then we will interpret this as + * request for the root inode. + */ + + if (!path || *path == 0 || strcmp(path, "/") == 0) + { + return root_inode; + } + + /* We don't know what to do with relative pathes */ + + if (*path != '/') + { + return NULL; + } + + /* Find the node matching the path. */ + + inode_semtake(); + node = inode_search(&path, (FAR void*)NULL, (FAR void*)NULL, relpath); + if (node) + { + + /* Is this a not in the psuedo filesystem? */ + + if (INODE_IS_MOUNTPT(node)) + { + /* Yes, then return the inode itself as the 'root' of + * the directory. The actually directory is at relpath into the + * mounted filesystem. Increment the count of references + * on the inode. + */ + + root = node; + root->i_crefs++; + } + else + { + /* It is a node in the psuedo filesystem. Does the inode have a child? + * If so that the child would be the 'root' of a list of nodes under + * the directory. + */ + + root = node->i_child; + if (root) + { + /* If found, then increment the count of + * references on the child node. + */ + + root->i_crefs++; + } + } + } + inode_semgive(); + return root; +} + +/************************************************************ + * Name: fs_openmountptdir + ************************************************************/ + +static inline int fs_openmountptdir(struct inode *inode, const char *relpath, + struct internal_dir_s *dir) +{ +#warning "Mountpoint support not implemented" + return -ENOSYS; +} + /************************************************************ * Public Functions ************************************************************/ @@ -87,18 +174,20 @@ FAR DIR *opendir(const char *path) { FAR struct inode *inode; FAR struct internal_dir_s *dir; + const char *relpath; + int ret; /* Get an inode corresponding to the path. On successful * return, we will hold on reference count on the inode. */ - inode = inode_finddir(path); + inode = fs_finddirnode(path, &relpath); if (!inode) { /* 'path' is not a directory.*/ - *get_errno_ptr() = ENOTDIR; - return NULL; + ret = ENOTDIR; + goto errout; } /* Allocate a type DIR -- which is little more than an inode @@ -110,17 +199,50 @@ FAR DIR *opendir(const char *path) { /* Insufficient memory to complete the operation.*/ - *get_errno_ptr() = ENOMEM; - inode_release(inode); - return NULL; + ret = ENOMEM; + goto errout_with_inode; } - /* Populate the DIR structure and return it to the caller */ + /* Populate the DIR structure and return it to the caller. The way that + * we do this depends on whenever this is a "normal" psuedo-file-system + * inode or a file system mountpoint. + */ + + dir->root = inode; /* Save the inode where we start */ + dir->position = 0; /* This is the position in the read stream */ + + /* Is this a not in the psuedo filesystem? */ + + if (INODE_IS_MOUNTPT(inode)) + { + /* The node is a file system mointpoint */ + + ret = fs_openmountptdir(inode, relpath, dir); + if (ret < 0) + { + ret = -ret; + goto errout_with_direntry; + } + } + else + { + /* The node is part of the root psuedo file system */ + + inode_addref(inode); /* Now we have two references on inode */ + dir->u.psuedo.next = inode; /* This is the next node to use for readdir() */ + } - dir->root = inode; /* Save where we started in case we rewind */ - inode_addref(inode); /* Now we have two references on inode */ - dir->next = inode; /* This is the next node to use for readdir() */ return ((DIR*)dir); + + /* Nasty goto's make error handling simpler */ + +errout_with_direntry: + free(dir); +errout_with_inode: + inode_release(inode); +errout: + *get_errno_ptr() = ret; + return NULL; } #endif /* CONFIG_NFILE_DESCRIPTORS */ diff --git a/nuttx/fs/fs_readdir.c b/nuttx/fs/fs_readdir.c index 54a880328..4c2d79227 100644 --- a/nuttx/fs/fs_readdir.c +++ b/nuttx/fs/fs_readdir.c @@ -49,6 +49,68 @@ * Private Functions ************************************************************/ +/************************************************************ + * Name: readpsuedodir + ************************************************************/ + +static inline FAR struct dirent *readpsuedodir(struct internal_dir_s *idir) +{ + FAR struct inode *prev; + + /* Check if we are at the end of the list */ + + if (!idir->u.psuedo.next) + { + return NULL; + } + + /* Copy the inode name into the dirent structure */ + + strncpy(idir->dir.d_name, idir->u.psuedo.next->i_name, NAME_MAX+1); + + /* If the node has file operations, we will say that it is + * a file. + */ + + idir->dir.d_type = 0; + if (idir->u.psuedo.next->u.i_ops) + { + idir->dir.d_type |= DTYPE_FILE; + } + + /* If the node has child node(s), then we will say that it + * is a directory. NOTE: that the node can be both! + */ + + if (idir->u.psuedo.next->i_child || !idir->u.psuedo.next->u.i_ops) + { + idir->dir.d_type |= DTYPE_DIRECTORY; + } + + /* Now get the inode to vist next time that readdir() is called */ + + inode_semtake(); + + prev = idir->u.psuedo.next; + idir->u.psuedo.next = prev->i_peer; /* The next node to visit */ + + if (idir->u.psuedo.next) + { + /* Increment the reference count on this next node */ + + idir->u.psuedo.next->i_crefs++; + } + + inode_semgive(); + + if (prev) + { + inode_release(prev); + } + + return &idir->dir; +} + /************************************************************ * Public Functions ************************************************************/ @@ -80,66 +142,34 @@ FAR struct dirent *readdir(DIR *dirp) { FAR struct internal_dir_s *idir = (struct internal_dir_s *)dirp; - FAR struct inode *prev; - if (!idir) + /* Sanity checks */ + + if (!idir || !idir->root) { *get_errno_ptr() = EBADF; return NULL; } - /* Check if we are at the end of the list */ + /* The way we handle the readdir depends on the type of inode + * that we are dealing with. + */ - if (!idir->next) + if (INODE_IS_MOUNTPT(idir->root)) { + /* The node is a file system mointpoint */ + +#warning "Mountpoint support not implemented" + *get_errno_ptr() = ENOSYS; return NULL; } - - /* Copy the inode name into the dirent structure */ - - strncpy(idir->dir.d_name, idir->next->i_name, NAME_MAX+1); - - /* If the node has file operations, we will say that it is - * a file. - */ - - idir->dir.d_type = 0; - if (idir->next->u.i_ops) + else { - idir->dir.d_type |= DTYPE_FILE; + /* The node is part of the root psuedo file system, release + * our contained reference to the 'next' inode. + */ + return readpsuedodir(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 (idir->next->i_child || !idir->next->u.i_ops) - { - idir->dir.d_type |= DTYPE_DIRECTORY; - } - - /* Now get the inode to vist next time that readdir() is called */ - - inode_semtake(); - - prev = idir->next; - idir->next = prev->i_peer; /* The next node to visit */ - - if (idir->next) - { - /* Increment the reference count on this next node */ - - idir->next->i_crefs++; - } - - inode_semgive(); - - if (prev) - { - inode_release(prev); - } - - return &idir->dir; } #endif /* CONFIG_NFILE_DESCRIPTORS */ diff --git a/nuttx/fs/fs_rewinddir.c b/nuttx/fs/fs_rewinddir.c index a5de2784b..0f08da250 100644 --- a/nuttx/fs/fs_rewinddir.c +++ b/nuttx/fs/fs_rewinddir.c @@ -48,6 +48,35 @@ * Private Functions ************************************************************/ +#if CONFIG_NFILE_DESCRIPTORS > 0 + +static inline void rewindpsuedodir(struct internal_dir_s *idir) +{ + struct inode *prev; + + inode_semtake(); + + /* Reset the position to the beginning */ + + prev = idir->u.psuedo.next; /* (Save to delete later) */ + idir->u.psuedo.next = idir->root; /* The next node to visit */ + idir->position = 0; /* Reset position */ + + /* Increment the reference count on the root=next node. We + * should now have two references on the inode. + */ + + idir->root->i_crefs++; + inode_semgive(); + + /* Then release the reference to the old next inode */ + + if (prev) + { + inode_release(prev); + } +} + /************************************************************ * Public Functions ************************************************************/ @@ -68,33 +97,32 @@ * ************************************************************/ -#if CONFIG_NFILE_DESCRIPTORS > 0 - void rewinddir(FAR DIR *dirp) { struct internal_dir_s *idir = (struct internal_dir_s *)dirp; - struct inode *prev; - if (idir) + /* Sanity checks */ + + if (!idir || !idir->root) { - inode_semtake(); + return; + } - prev = idir->next; - idir->next = idir->root; /* The next node to visit */ + /* The way we handle the readdir depends on the type of inode + * that we are dealing with. + */ - if (idir->next) - { - /* Increment the reference count on this next node */ + if (INODE_IS_MOUNTPT(idir->root)) + { + /* The node is a file system mointpoint */ - idir->next->i_crefs++; - } +#warning "Mountpoint support not implemented" + } + else + { + /* The node is part of the root psuedo file system */ - inode_semgive(); - - if (prev) - { - inode_release(prev); - } + rewindpsuedodir(idir); } } diff --git a/nuttx/fs/fs_seekdir.c b/nuttx/fs/fs_seekdir.c index aa0ee907d..bdc03d88c 100644 --- a/nuttx/fs/fs_seekdir.c +++ b/nuttx/fs/fs_seekdir.c @@ -48,6 +48,61 @@ * Private Functions ************************************************************/ +#if CONFIG_NFILE_DESCRIPTORS > 0 + +static inline void seekpsuedodir(struct internal_dir_s *idir, off_t offset) +{ + struct inode *curr; + 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 poisition. Otherwise, we will + * "rewind" to the root dir. + */ + + if ( offset < idir->position ) + { + pos = 0; + curr = idir->root; + } + else + { + pos = idir->position; + curr = idir->u.psuedo.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 && pos != offset; pos++, curr = curr->i_peer); + + /* Now get the inode to vist next time that readdir() is called */ + + prev = idir->u.psuedo.next; + idir->u.psuedo.next = curr; /* The next node to visit (might be null) */ + idir->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); + } +} + /************************************************************ * Public Functions ************************************************************/ @@ -71,46 +126,32 @@ * ************************************************************/ -#if CONFIG_NFILE_DESCRIPTORS > 0 - void seekdir(FAR DIR *dirp, off_t offset) { struct internal_dir_s *idir = (struct internal_dir_s *)dirp; - struct inode *curr; - struct inode *prev; - off_t i; - if (idir) + /* Sanity checks */ + + if (!idir || !idir->root) { - /* 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. - */ + return; + } - inode_semtake(); - for (i = 0, curr = idir->root; - curr && i != offset; - i++, curr = curr->i_peer); + /* The way we handle the readdir depends on the type of inode + * that we are dealing with. + */ - /* Now get the inode to vist next time that readdir() is called */ + if (INODE_IS_MOUNTPT(idir->root)) + { + /* The node is a file system mointpoint */ - prev = idir->next; - idir->next = curr; /* The next node to visit */ +#warning "Mountpoint support not implemented" + } + else + { + /* The node is part of the root psuedo file system */ - if (curr) - { - /* Increment the reference count on this next node */ - - curr->i_crefs++; - } - - inode_semgive(); - - if (prev) - { - inode_release(prev); - } + seekpsuedodir(idir, offset); } } diff --git a/nuttx/fs/fs_telldir.c b/nuttx/fs/fs_telldir.c index 781a46469..31103d777 100644 --- a/nuttx/fs/fs_telldir.c +++ b/nuttx/fs/fs_telldir.c @@ -77,30 +77,16 @@ off_t telldir(FAR DIR *dirp) { struct internal_dir_s *idir = (struct internal_dir_s *)dirp; - struct inode *curr; - off_t offs; - if (!idir) + if (!idir || !idir->root) { *get_errno_ptr() = EBADF; - return -1; + return (off_t)-1; } - /* Traverse the peer list starting at the 'root' of the - * the list until we find the 'next' node. If devices - * are being registered and unregistered, then this can - * be a very unpredictable operation. - */ + /* Just return the current position */ - inode_semtake(); - for (offs = 0, curr = idir->root; - curr && curr != idir->next; - offs++, curr = curr->i_peer); - - /* We should have an offset now corresponding to idir->next.*/ - - inode_semgive(); - return offs; + return idir->position; } #endif /* CONFIG_NFILE_DESCRIPTORS */