From 92305e400a11f0e314a0c1b938db1088b78eca5e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 2 Feb 2017 10:39:41 -0600 Subject: [PATCH 1/7] Soft links: Initial, incompete implementation --- fs/Kconfig | 13 ++++ fs/inode/fs_inode.c | 25 ++++++- fs/vfs/Make.defs | 12 ++- fs/vfs/fs_rmdir.c | 5 +- fs/vfs/fs_softlink.c | 169 ++++++++++++++++++++++++++++++++++++++++++ include/nuttx/fs/fs.h | 25 +++++-- include/unistd.h | 3 +- 7 files changed, 239 insertions(+), 13 deletions(-) create mode 100644 fs/vfs/fs_softlink.c diff --git a/fs/Kconfig b/fs/Kconfig index 603d9a51152..6b67520fd2b 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -40,6 +40,19 @@ config DISABLE_PSEUDOFS_OPERATIONS However, in practical embedded system, they are seldom needed and you can save a little FLASH space by disabling the capability. +config PSEUDOFS_SOFTLINKS + bool "Pseudo-filesystem soft links" + default y if DEFAULT_SMALL + default n if !DEFAULT_SMALL + depends on !DISABLE_PSEUDOFS_OPERATIONS + ---help--- + Enable support for soft links in the pseudeo file system. Soft + links are not supported within mounted volumes by any NuttX file + system. However, if this option is selected, then soft links + may be add in the pseudo file system. This might be useful, for + to link a directory in the pseudo-file system, such as /bin, to + to a directory in a mounted volume, say /mnt/sdcard/bin. + config FS_READABLE bool default n diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index 3658ad5e44f..e77c157415d 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/inode/fs_inode.c * - * Copyright (C) 2007-2009, 2011-2012, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2012, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -345,6 +346,7 @@ FAR struct inode *inode_search(FAR const char **path, { *relpath = name; } + break; } else @@ -401,8 +403,29 @@ void inode_free(FAR struct inode *node) if (node != NULL) { +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* Symbol links should never have peers or children */ + + DEBUGASSERT(!INODE_IS_SOFTLINK(node)) || + (node->i_peer == NULL && node->i_child == NULL) +#endif + + /* Free all peers and children of this i_node */ + inode_free(node->i_peer); inode_free(node->i_child); + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* If the inode is a symbolic link, the free the path to the linked + * entity. + */ + + if (INODE_IS_SOFTLINK(node) && inode->u.i_link != NULL) + { + kmm_free(node->u.i_link); + } +#endif + kmm_free(node); } } diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 645e23f97e4..9b5e6911afb 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # fs/vfs/Make.defs # -# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. +# Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -43,7 +43,11 @@ ifneq ($(CONFIG_NSOCKET_DESCRIPTORS),0) CSRCS += fs_close.c fs_read.c fs_write.c fs_ioctl.c -# Support for network access using streams +ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) +CSRCS += fs_softlink.c +endif + +# Stream support ifneq ($(CONFIG_NFILE_STREAMS),0) CSRCS += fs_fdopen.c @@ -86,6 +90,10 @@ endif CSRCS += fs_pread.c fs_pwrite.c +ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) +CSRCS += fs_softlink.c +endif + # Stream support ifneq ($(CONFIG_NFILE_STREAMS),0) diff --git a/fs/vfs/fs_rmdir.c b/fs/vfs/fs_rmdir.c index ecef33558e3..d3e15bce139 100644 --- a/fs/vfs/fs_rmdir.c +++ b/fs/vfs/fs_rmdir.c @@ -84,8 +84,9 @@ int rmdir(FAR const char *pathname) const char *relpath = NULL; int errcode; - /* Get an inode for this file. inode_find() automatically increments the - * reference count on the inode if one is found. + /* Get an inode for the directory (or for the mountpoint containing the + * directory). inode_find() automatically increments the reference count + * on the inode if one is found. */ inode = inode_find(pathname, &relpath); diff --git a/fs/vfs/fs_softlink.c b/fs/vfs/fs_softlink.c new file mode 100644 index 00000000000..483bcb4ffab --- /dev/null +++ b/fs/vfs/fs_softlink.c @@ -0,0 +1,169 @@ +/**************************************************************************** + * fs/vfs/fs_softlink.c + * + * Copyright (C) 2017 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 NuttX 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 "inode/inode.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: link + * + * Description: + * The link() function will create a new link (directory entry) for the + * existing file, path1. This implementation is simplied for use with + * NuttX in these ways: + * + * - Links may be created only within the NuttX top-level, pseudo file + * system. No file system currently supported by NuttX provides + * symbolic links. + * - For the same reason, only soft links are implemented. + * - File privileges are ignored. + * - c_time is not updated. + * + * Input Parameters: + * path1 - Points to a pathname naming an existing file. + * path2 - Points to a pathname naming the new directory entry to be created. + * + * Returned Value: + * On success, zero (OK) is returned. Otherwise, -1 (ERROR) is returned + * the the errno variable is set appropriately. + * + ****************************************************************************/ + +int link(FAR const char *path1, FAR const char *path2) +{ + FAR struct inode *inode; + int errcode; + int ret; + + DEBUGASSERT(path1 != NULL && path2 != NULL && *path2 != '\0'); + + /* Check that no inode exists at the 'path2' and that the path up to 'path2' + * does not lie on a mounted volume. + */ + + inode = inode_find(pathname, NULL); + if (inode != NULL) + { +#ifndef CONFIG_DISABLE_MOUNTPOINT + /* Check if the inode is a mountpoint. */ + + if (INODE_IS_MOUNTPT(inode)) + { + /* Symbol links within the mounted volume are not supported */ + + errcode = ENOSYS; + } + else +#endif + { + /* A node already exists in the pseudofs at 'path2' */ + + errorcode = EEXIST; + } + + goto errout_with_inode; + } + + /* No inode exists that contains this path. Create a new inode in the + * pseudo-filesystem at this location. + */ + + else + { + /* Copy path2 */ + + FAR char newpath2 = strdup(path2); + if (newpath2 == NULL) + { + errcode = ENOMEM; + goto errout; + } + + /* Create an inode in the pseudo-filesystem at this path. + * NOTE that the new inode will be created with a reference + * count of zero. + */ + + inode_semtake(); + ret = inode_reserve(pathname, &inode); + inode_semgive(); + + if (ret < 0) + { + kmm_free(newpath2) + errcode = -ret; + goto errout; + } + + /* Initialize the inode */ + + INODE_SET_SOFTLINK(inode); + inode->u.i_link = newpath2; + inode->i_crefs = 1; + } + + /* Symbolic link successfully created */ + + return OK; + +errout_with_inode: + inode_release(inode); +errout: + set_errno(errcode); + return ERROR; +} + +#endif /* CONFIG_PSEUDOFS_SOFTLINKS */ diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 238a6b8ef96..8ec3bc83da7 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/fs/fs.h * - * Copyright (C) 2007-2009, 2011-2013, 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2013, 2015-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -66,12 +66,17 @@ #define __FS_FLAG_EOF (1 << 0) /* EOF detected by a read operation */ #define __FS_FLAG_ERROR (1 << 1) /* Error detected by any operation */ -/* Inode i_flag values */ +/* Inode i_flag values: + * + * Bit 0-3: Inode type (Bit 4 indicates internal OS types) + * Bit 4: Set if inode has been unlinked and is pending removal. + */ #define FSNODEFLAG_TYPE_MASK 0x00000007 /* Isolates type field */ #define FSNODEFLAG_TYPE_DRIVER 0x00000000 /* Character driver */ #define FSNODEFLAG_TYPE_BLOCK 0x00000001 /* Block driver */ #define FSNODEFLAG_TYPE_MOUNTPT 0x00000002 /* Mount point */ +#define FSNODEFLAG_TYPE_SOFTLINK 0x00000003 /* Soft link */ #define FSNODEFLAG_TYPE_SPECIAL 0x00000004 /* Special OS type */ #define FSNODEFLAG_TYPE_NAMEDSEM 0x00000004 /* Named semaphore */ #define FSNODEFLAG_TYPE_MQUEUE 0x00000005 /* Message Queue */ @@ -86,6 +91,7 @@ #define INODE_IS_DRIVER(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_DRIVER) #define INODE_IS_BLOCK(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_BLOCK) #define INODE_IS_MOUNTPT(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT) +#define INODE_IS_SOFTLINK(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) #define INODE_IS_NAMEDSEM(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM) #define INODE_IS_MQUEUE(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MQUEUE) #define INODE_IS_SHM(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SHM) @@ -101,6 +107,7 @@ #define INODE_SET_DRIVER(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_DRIVER) #define INODE_SET_BLOCK(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_BLOCK) #define INODE_SET_MOUNTPT(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT) +#define (i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) #define INODE_SET_NAMEDSEM(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM) #define INODE_SET_MQUEUE(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MQUEUE) #define INODE_SET_SHM(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SHM) @@ -309,16 +316,19 @@ struct mountpt_operations union inode_ops_u { - FAR const struct file_operations *i_ops; /* Driver operations for inode */ + FAR const struct file_operations *i_ops; /* Driver operations for inode */ #ifndef CONFIG_DISABLE_MOUNTPOINT - FAR const struct block_operations *i_bops; /* Block driver operations */ - FAR const struct mountpt_operations *i_mops; /* Operations on a mountpoint */ + FAR const struct block_operations *i_bops; /* Block driver operations */ + FAR const struct mountpt_operations *i_mops; /* Operations on a mountpoint */ #endif #ifdef CONFIG_FS_NAMED_SEMAPHORES - FAR struct nsem_inode_s *i_nsem; /* Named semaphore */ + FAR struct nsem_inode_s *i_nsem; /* Named semaphore */ #endif #ifndef CONFIG_DISABLE_MQUEUE - FAR struct mqueue_inode_s *i_mqueue; /* POSIX message queue */ + FAR struct mqueue_inode_s *i_mqueue; /* POSIX message queue */ +#endif +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + FAR char *i_link; /* Full path to link */ #endif }; @@ -337,6 +347,7 @@ struct inode FAR void *i_private; /* Per inode driver private data */ char i_name[1]; /* Name of inode (variable) */ }; + #define FSNODE_SIZE(n) (sizeof(struct inode) + (n)) /* This is the underlying representation of an open file. A file diff --git a/include/unistd.h b/include/unistd.h index 7361b412eae..e5e69f261b3 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/unistd.h * - * Copyright (C) 2007-2009, 2013-2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013-2014, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -190,6 +190,7 @@ FAR char *getcwd(FAR char *buf, size_t size); int access(FAR const char *path, int amode); int rmdir(FAR const char *pathname); int unlink(FAR const char *pathname); +int link(FAR const char *path1, FAR const char *path2); /* Execution of programs from files */ From bdc002fadcbcb3222aeac84af1e38433decf696a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 2 Feb 2017 13:01:21 -0600 Subject: [PATCH 2/7] Finish implementation of soft links. --- fs/inode/fs_inode.c | 134 +++++++++++++++++++++++++++++++++++++--- fs/inode/fs_inodefind.c | 38 +++++++++++- fs/inode/inode.h | 32 ++++++++-- fs/vfs/fs_softlink.c | 12 +++- fs/vfs/fs_unlink.c | 16 ++--- include/limits.h | 12 ++++ include/nuttx/fs/fs.h | 2 +- 7 files changed, 222 insertions(+), 24 deletions(-) diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index e77c157415d..b8f1bda45b0 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -167,6 +168,45 @@ static int _inode_compare(FAR const char *fname, } } +/**************************************************************************** + * Name: _inode_dereference + * + * Description: + * If the inode is a soft link, then (1) get the name of the full path of + * the soft link, (2) recursively look-up the inode referenced by the soft + * link, and (3) return the inode referenced by the soft link. + * + * Assumptions: + * The caller holds the g_inode_sem semaphore + * + ****************************************************************************/ + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS +static inline FAR struct inode * +_inode_dereference(FAR struct inode *node, FAR struct inode **peer, + FAR struct inode **parent, FAR const char **relpath) +{ + unsigned int count = 0; + + /* An infinite loop is avoided only by the loop count. + * + * REVISIT: The ELOOP error should be reported to the application in that + * case but there is no simple mechanism to do that. + */ + + while (node != NULL && INODE_IS_SOFTLINK(node)) + { + node = inode_search_nofollow(node->u.i_link, peer, parent, relpath); + if (++count > SYMLOOP_MAX) + { + return NULL; + } + } + + return node; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -275,28 +315,40 @@ void inode_semgive(void) } /**************************************************************************** - * Name: inode_search + * Name: inode_search and inode_search_nofollow * * Description: * Find the inode associated with 'path' returning the inode references * and references to its companion nodes. * + * Both versions will follow soft links in path leading up to the terminal + * node. inode_search() will deference that terminal node, + * inode_search_nofollow will not. + * * Assumptions: * The caller holds the g_inode_sem semaphore * ****************************************************************************/ +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + +FAR struct inode *inode_search_nofollow(FAR const char **path, + FAR struct inode **peer, + FAR struct inode **parent, + FAR const char **relpath) +#else FAR struct inode *inode_search(FAR const char **path, FAR struct inode **peer, FAR struct inode **parent, FAR const char **relpath) +#endif { FAR const char *name = *path + 1; /* Skip over leading '/' */ FAR struct inode *node = g_root_inode; FAR struct inode *left = NULL; FAR struct inode *above = NULL; - while (node) + while (node != NULL) { int result = _inode_compare(name, node); @@ -319,6 +371,24 @@ FAR struct inode *inode_search(FAR const char **path, else if (result > 0) { +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* If the inode in the is a soft link and this is the inode at + * at the head of the peer list and not the final node in the + * path), then (1) get the name of the full path of the soft + * link, (2) recursively look-up the inode referenced by the + * soft link, and (3) use the peer of that inode instead. + */ + + FAR const char *nextname = inode_nextname(name); + if (*nextname != '\0') + { + node = _inode_dereference(node, NULL, &above, relpath); + if (node == NULL) + { + break; + } + } +#endif left = node; node = node->i_peer; } @@ -327,15 +397,15 @@ FAR struct inode *inode_search(FAR const char **path, else { - /* Now there are three more possibilities: - * (1) This is the node that we are looking for or, + /* Now there are three remaining possibilities: + * (1) This is the node that we are looking for. * (2) The node we are looking for is "below" this one. * (3) This node is a mountpoint and will absorb all request * below this one */ name = inode_nextname(name); - if (!*name || INODE_IS_MOUNTPT(node)) + if (*name == '\0' || INODE_IS_MOUNTPT(node)) { /* Either (1) we are at the end of the path, so this must be the * node we are looking for or else (2) this node is a mountpoint @@ -347,15 +417,38 @@ FAR struct inode *inode_search(FAR const char **path, *relpath = name; } +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* NOTE that if the terminal inode is a soft link, it is not + * deferenced in this case. The raw inode is returned. + * + * In that case a wrapper function will perform that operation. + */ +#endif break; } else { - /* More to go, keep looking at the next level "down" */ + /* More to go.. */ + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* If this intermediate inode in the is a soft link, then (1) + * get the name of the full path of the soft link, (2) recursively + * look-up the inode referenced by the sof link, and (3) + * continue searching with that inode instead. + */ + + node = _inode_dereference(node, NULL, NULL, relpath); + if (node == NULL) + { + break; + } +#endif + + /* Keep looking at the next level "down" */ above = node; left = NULL; - node = node->i_child; + node = node->i_child; } } } @@ -389,6 +482,33 @@ FAR struct inode *inode_search(FAR const char **path, return node; } +#ifdef CONFIG_PSEUDOFS_SOFTLINKS +FAR struct inode *inode_search(FAR const char **path, + FAR struct inode **peer, + FAR struct inode **parent, + FAR const char **relpath) +{ + /* Lookup the terminal inode */ + + FAR struct inode *node = inode_search_nofollow(path, peer, parent, relpath); + + /* Did we find it? */ + + if (node != NULL) + { + /* Yes.. If the terminal inode in the is a soft link, then (1) get + * the name of the full path of the soft link, (2) recursively + * look-up the inode referenced by the soft link, and (3) + * return that inode instead. + */ + + return _inode_dereference(node, peer, parent, relpath); + } + + return node; +} +#endif + /**************************************************************************** * Name: inode_free * diff --git a/fs/inode/fs_inodefind.c b/fs/inode/fs_inodefind.c index 3ff249d348d..38f15b595ef 100644 --- a/fs/inode/fs_inodefind.c +++ b/fs/inode/fs_inodefind.c @@ -49,19 +49,23 @@ ****************************************************************************/ /**************************************************************************** - * Name: inode_find + * Name: inode_find and indode_find_nofollow * * Description: * This is called from the open() logic to get a reference to the inode * associated with a path. * + * Both versions will follow soft links in path leading up to the terminal + * node. inode_find() will deference that terminal node, + * indode_find_nofollow no follow will not. + * ****************************************************************************/ FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath) { FAR struct inode *node; - if (path == NULL || path[0] == '\0' || path[0] != '/') + if (path == NULL || *path != '/') { return NULL; } @@ -71,7 +75,8 @@ FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath) */ inode_semtake(); - node = inode_search(&path, (FAR struct inode**)NULL, (FAR struct inode**)NULL, relpath); + node = inode_search(&path, (FAR struct inode**)NULL, + (FAR struct inode**)NULL, relpath); if (node) { node->i_crefs++; @@ -81,3 +86,30 @@ FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath) return node; } +#ifdef CONFIG_PSEUDOFS_SOFTLINKS +FAR struct inode *inode_find_nofollow(FAR const char *path, + FARconst char **relpath) +{ + FAR struct inode *node; + + if (path == NULL || *path != '/') + { + return NULL; + } + + /* Find the node matching the path. If found, increment the count of + * references on the node. + */ + + inode_semtake(); + node = inode_search_nofollow(&path, (FAR struct inode**)NULL, + (FAR struct inode**)NULL, relpath); + if (node) + { + node->i_crefs++; + } + + inode_semgive(); + return node; +} +#endif diff --git a/fs/inode/inode.h b/fs/inode/inode.h index f909d74ef17..31532490c78 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -112,14 +112,18 @@ void inode_semtake(void); void inode_semgive(void); /**************************************************************************** - * Name: inode_search + * Name: inode_search and inode_search_nofollow * * Description: * Find the inode associated with 'path' returning the inode references * and references to its companion nodes. * + * Both versions will follow soft links in path leading up to the terminal + * node. inode_search() will deference that terminal node, + * inode_search_nofollow will not. + * * Assumptions: - * The caller holds the tree_sem + * The caller holds the g_inode_sem semaphore * ****************************************************************************/ @@ -128,6 +132,15 @@ FAR struct inode *inode_search(FAR const char **path, FAR struct inode **parent, FAR const char **relpath); +#ifdef CONFIG_PSEUDOFS_SOFTLINKS +FAR struct inode *inode_search_nofollow(FAR const char **path, + FAR struct inode **peer, + FAR struct inode **parent, + FAR const char **relpath) +#else +# define inode_search_nofollow(p,l,a,r) inode_search(p,l,a,r) +#endif + /**************************************************************************** * Name: inode_free * @@ -205,15 +218,26 @@ FAR struct inode *inode_unlink(FAR const char *path); int inode_remove(FAR const char *path); /**************************************************************************** - * Name: inode_find + * Name: inode_find and indode_find_nofollow * * Description: * This is called from the open() logic to get a reference to the inode * associated with a path. * + * Both versions will follow soft links in path leading up to the terminal + * node. inode_find() will deference that terminal node, + * indode_find_nofollow no follow will not. + * ****************************************************************************/ -FAR struct inode *inode_find(FAR const char *path, const char **relpath); +FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath); + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS +FAR struct inode *inode_find_nofollow(FAR const char *path, + FARconst char **relpath); +#else +# define inode_find_nofollow(p,r) inode_find(p,r) +#endif /**************************************************************************** * Name: inode_addref diff --git a/fs/vfs/fs_softlink.c b/fs/vfs/fs_softlink.c index 483bcb4ffab..225bf5b61b3 100644 --- a/fs/vfs/fs_softlink.c +++ b/fs/vfs/fs_softlink.c @@ -88,7 +88,15 @@ int link(FAR const char *path1, FAR const char *path2) int errcode; int ret; - DEBUGASSERT(path1 != NULL && path2 != NULL && *path2 != '\0'); + /* Both paths must be absolute. We need only check path2 here. path1 will + * be checked by inode find. + */ + + if (path2 == NULL || *path2 != '/') + { + errode = EINVAL; + goto errout; + } /* Check that no inode exists at the 'path2' and that the path up to 'path2' * does not lie on a mounted volume. @@ -129,7 +137,7 @@ int link(FAR const char *path1, FAR const char *path2) if (newpath2 == NULL) { errcode = ENOMEM; - goto errout; + goto errout; } /* Create an inode in the pseudo-filesystem at this path. diff --git a/fs/vfs/fs_unlink.c b/fs/vfs/fs_unlink.c index 9de8ea2f2f7..ea754fed5c6 100644 --- a/fs/vfs/fs_unlink.c +++ b/fs/vfs/fs_unlink.c @@ -85,9 +85,11 @@ int unlink(FAR const char *pathname) int errcode; int ret; - /* Get an inode for this file */ + /* Get an inode for this file (without deference the final node in the path + * which may be a symbolic link) + */ - inode = inode_find(pathname, &relpath); + inode = inode_find_nofollow(pathname, &relpath); if (!inode) { /* There is no inode that includes in this path */ @@ -124,17 +126,17 @@ int unlink(FAR const char *pathname) #endif #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS - /* If this is a "dangling" pseudo-file node (i.e., it has operations) then rm - * should remove the node. + /* If this is a "dangling" pseudo-file node (i.e., it has no operations) + * or a soft link, then rm should remove the node. */ - if (!INODE_IS_SPECIAL(inode) && inode->u.i_ops) + if (!INODE_IS_SPECIAL(inode)) { /* If this is a pseudo-file node (i.e., it has no operations) - * then rmdir should remove the node. + * then unlink should remove the node. */ - if (inode->u.i_ops) + if (inode->u.i_ops != NULL) { inode_semtake(); diff --git a/include/limits.h b/include/limits.h index 3479e595953..27c616b2a73 100644 --- a/include/limits.h +++ b/include/limits.h @@ -111,6 +111,12 @@ * * _POSIX_SEM_NSEMS_MAX Max number of open semaphores per task * _POSIX_SEM_VALUE_MAX Max value a semaphore may have + * + * Required for symbolic links + * _POSIX_SYMLOOP_MAX Maximum number of symbolic links that can be + * reliably traversed in the resolution of a pathname + * in the absence of a loop. + * */ #define _POSIX_ARG_MAX 4096 @@ -143,6 +149,10 @@ #define _POSIX_RTSIG_MAX 31 #define _POSIX_SIGQUEUE_MAX 32 +/* Required for symbolic links */ + +#define _POSIX_SYMLOOP_MAX 100 + /* Required for POSIX timers. * * _POSIX_DELAYTIMER_MAX is the number of timer expiration overruns. @@ -205,6 +215,8 @@ #define RTSIG_MAX _POSIX_RTSIG_MAX #define SIGQUEUE_MAX _POSIX_SIGQUEUE_MAX +#define SYMLOOP_MAX _POSIX_SYMLOOP_MAX + #define DELAYTIMER_MAX _POSIX_DELAYTIMER_MAX #define TIMER_MAX _POSIX_TIMER_MAX #define CLOCKRES_MIN _POSIX_CLOCKRES_MIN diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 8ec3bc83da7..cf568658024 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -125,7 +125,7 @@ * descriptor instead. * * This case is when SUSv1 pseudo-terminals are used (CONFIG_PSEUDOTERM_SUSV1=y). - * In this case, the output is encoded and decoded using these macros in + * In this case, the output is encoded and decoded using these macros in * order to support (a) returning file descriptor 0 (which really should * not happen), and (b) avoiding confusion if some other open method returns * a positive, non-zero value which is not a file descriptor. From 35d738d85f47faf711c22828428b5b40f6abd10c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 2 Feb 2017 15:24:39 -0600 Subject: [PATCH 3/7] Soft links: Fix compile problems on first build with soft links enabled. --- fs/Kconfig | 3 +-- fs/inode/fs_inode.c | 9 +++++---- fs/inode/fs_inodefind.c | 2 +- fs/inode/inode.h | 4 ++-- fs/vfs/fs_softlink.c | 16 +++++++++------- include/nuttx/fs/fs.h | 2 +- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/fs/Kconfig b/fs/Kconfig index 6b67520fd2b..05ab5daea93 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -42,8 +42,7 @@ config DISABLE_PSEUDOFS_OPERATIONS config PSEUDOFS_SOFTLINKS bool "Pseudo-filesystem soft links" - default y if DEFAULT_SMALL - default n if !DEFAULT_SMALL + default n depends on !DISABLE_PSEUDOFS_OPERATIONS ---help--- Enable support for soft links in the pseudeo file system. Soft diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index b8f1bda45b0..1da4069c293 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -196,7 +196,8 @@ _inode_dereference(FAR struct inode *node, FAR struct inode **peer, while (node != NULL && INODE_IS_SOFTLINK(node)) { - node = inode_search_nofollow(node->u.i_link, peer, parent, relpath); + node = inode_search_nofollow((FAR const char **)&node->u.i_link, + peer, parent, relpath); if (++count > SYMLOOP_MAX) { return NULL; @@ -526,8 +527,8 @@ void inode_free(FAR struct inode *node) #ifdef CONFIG_PSEUDOFS_SOFTLINKS /* Symbol links should never have peers or children */ - DEBUGASSERT(!INODE_IS_SOFTLINK(node)) || - (node->i_peer == NULL && node->i_child == NULL) + DEBUGASSERT(!INODE_IS_SOFTLINK(node) || + (node->i_peer == NULL && node->i_child == NULL)); #endif /* Free all peers and children of this i_node */ @@ -540,7 +541,7 @@ void inode_free(FAR struct inode *node) * entity. */ - if (INODE_IS_SOFTLINK(node) && inode->u.i_link != NULL) + if (INODE_IS_SOFTLINK(node) && node->u.i_link != NULL) { kmm_free(node->u.i_link); } diff --git a/fs/inode/fs_inodefind.c b/fs/inode/fs_inodefind.c index 38f15b595ef..b5339c9b863 100644 --- a/fs/inode/fs_inodefind.c +++ b/fs/inode/fs_inodefind.c @@ -88,7 +88,7 @@ FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath) #ifdef CONFIG_PSEUDOFS_SOFTLINKS FAR struct inode *inode_find_nofollow(FAR const char *path, - FARconst char **relpath) + FAR const char **relpath) { FAR struct inode *node; diff --git a/fs/inode/inode.h b/fs/inode/inode.h index 31532490c78..529642bfa71 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -136,7 +136,7 @@ FAR struct inode *inode_search(FAR const char **path, FAR struct inode *inode_search_nofollow(FAR const char **path, FAR struct inode **peer, FAR struct inode **parent, - FAR const char **relpath) + FAR const char **relpath); #else # define inode_search_nofollow(p,l,a,r) inode_search(p,l,a,r) #endif @@ -234,7 +234,7 @@ FAR struct inode *inode_find(FAR const char *path, FAR const char **relpath); #ifdef CONFIG_PSEUDOFS_SOFTLINKS FAR struct inode *inode_find_nofollow(FAR const char *path, - FARconst char **relpath); + FAR const char **relpath); #else # define inode_find_nofollow(p,r) inode_find(p,r) #endif diff --git a/fs/vfs/fs_softlink.c b/fs/vfs/fs_softlink.c index 225bf5b61b3..b40a5ea9727 100644 --- a/fs/vfs/fs_softlink.c +++ b/fs/vfs/fs_softlink.c @@ -41,8 +41,10 @@ #include #include +#include #include +#include #include #include "inode/inode.h" @@ -94,7 +96,7 @@ int link(FAR const char *path1, FAR const char *path2) if (path2 == NULL || *path2 != '/') { - errode = EINVAL; + errcode = EINVAL; goto errout; } @@ -102,7 +104,7 @@ int link(FAR const char *path1, FAR const char *path2) * does not lie on a mounted volume. */ - inode = inode_find(pathname, NULL); + inode = inode_find(path1, NULL); if (inode != NULL) { #ifndef CONFIG_DISABLE_MOUNTPOINT @@ -110,7 +112,7 @@ int link(FAR const char *path1, FAR const char *path2) if (INODE_IS_MOUNTPT(inode)) { - /* Symbol links within the mounted volume are not supported */ + /* Symbolic links within the mounted volume are not supported */ errcode = ENOSYS; } @@ -119,7 +121,7 @@ int link(FAR const char *path1, FAR const char *path2) { /* A node already exists in the pseudofs at 'path2' */ - errorcode = EEXIST; + errcode = EEXIST; } goto errout_with_inode; @@ -133,7 +135,7 @@ int link(FAR const char *path1, FAR const char *path2) { /* Copy path2 */ - FAR char newpath2 = strdup(path2); + FAR char *newpath2 = strdup(path2); if (newpath2 == NULL) { errcode = ENOMEM; @@ -146,12 +148,12 @@ int link(FAR const char *path1, FAR const char *path2) */ inode_semtake(); - ret = inode_reserve(pathname, &inode); + ret = inode_reserve(path1, &inode); inode_semgive(); if (ret < 0) { - kmm_free(newpath2) + kmm_free(newpath2); errcode = -ret; goto errout; } diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index cf568658024..584ccef287f 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -107,7 +107,7 @@ #define INODE_SET_DRIVER(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_DRIVER) #define INODE_SET_BLOCK(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_BLOCK) #define INODE_SET_MOUNTPT(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT) -#define (i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) +#define INODE_SET_SOFTLINK(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) #define INODE_SET_NAMEDSEM(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM) #define INODE_SET_MQUEUE(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MQUEUE) #define INODE_SET_SHM(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SHM) From b39d96202162b5d431f175c5ee4aa3fa23d473c1 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 2 Feb 2017 17:11:08 -0600 Subject: [PATCH 4/7] Soft links: Update Documentation, rename file, add system calls --- Documentation/NuttShell.html | 198 ++++++++++++++++------------ arch/sim/src/nuttx-names.dat | 1 + fs/Makefile | 2 +- fs/vfs/Make.defs | 6 +- fs/vfs/{fs_softlink.c => fs_link.c} | 21 +-- include/nuttx/fs/fs.h | 2 +- include/sys/syscall.h | 15 ++- syscall/syscall.csv | 1 + syscall/syscall_lookup.h | 4 + syscall/syscall_stublookup.c | 2 + 10 files changed, 147 insertions(+), 105 deletions(-) rename fs/vfs/{fs_softlink.c => fs_link.c} (90%) diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html index 1d284dbea7a..8e4b2957d33 100644 --- a/Documentation/NuttShell.html +++ b/Documentation/NuttShell.html @@ -8,7 +8,7 @@

NuttShell (NSH)

-

Last Updated: August 4, 2016

+

Last Updated: February 2, 2017

@@ -263,223 +263,229 @@
- 2.30 List Directory Contents (ls) + 2.30 List to a File or Directory (ln)
- 2.31 Show information about installed OS modules (lsmod) + 2.31 List Directory Contents (ls)
- 2.32 Calculate MD5 (md5) + 2.32 Show information about installed OS modules (lsmod)
- 2.33 Access Memory (mb, mh, and mw) + 2.33 Calculate MD5 (md5)
- 2.34 Show Current Tasks and Threads (ps) + 2.34 Access Memory (mb, mh, and mw)
- 2.35 Create a Directory (mkdir) + 2.35 Show Current Tasks and Threads (ps)
- 2.36 Create a FAT Filesystem (mkfatfs) + 2.36 Create a Directory (mkdir)
- 2.37 Create a FIFO (mkfifo) + 2.37 Create a FAT Filesystem (mkfatfs)
- 2.38 Create a RAMDISK (mkrd) + 2.38 Create a FIFO (mkfifo)
- 2.39 Mount a File System (mount) + 2.39 Create a RAMDISK (mkrd)
- 2.40 Rename a File (mv) + 2.40 Mount a File System (mount)
- 2.41 Mount an NFS file system (nfsmount) + 2.41 Rename a File (mv)
- 2.42 Lookup a network address (nslookup) + 2.42 Mount an NFS file system (nfsmount)
- 2.43 Change a User's Password (passwd) + 2.43 Lookup a network address (nslookup)
- 2.44 Check Network Peer (ping/ping6) + 2.44 Change a User's Password (passwd)
- 2.45 Shut the system down (poweroff) + 2.45 Check Network Peer (ping/ping6)
- 2.46 Send File Via TFTP (put) + 2.46 Shut the system down (poweroff)
- 2.47 Show Current Working Directory (pwd) + 2.47 Send File Via TFTP (put)
- 2.48 Reset and reboot the system (reboot) + 2.48 Show Current Working Directory (pwd)
- 2.49 Remove a File (rm) + 2.49 Reset and reboot the system (reboot)
- 2.50 Remove a Directory (rmdir) + 2.50 Remove a File (rm)
- 2.51 Remove on OS Module (rmmod) + 2.51 Remove a Directory (rmdir)
- 2.52 Set an Environment Variable (set) + 2.52 Remove on OS Module (rmmod)
- 2.53 Execute an NSH Script (sh) + 2.53 Set an Environment Variable (set)
- 2.54 Shut the system down (shutdown) + 2.54 Execute an NSH Script (sh)
- 2.55 Wait for Seconds (sleep) + 2.55 Shut the system down (shutdown)
- 2.56 Time execution of another command (time) + 2.56 Wait for Seconds (sleep)
- 2.57 Unmount a File System (umount) + 2.57 Time execution of another command (time)
- 2.58 Print system information (uname) + 2.58 Unmount a File System (umount)
- 2.59 Unset an Environment Variable (unset) + 2.59 Print system information (uname)
- 2.60 URL Decode (urldecode) + 2.60 Unset an Environment Variable (unset)
- 2.61 URL Encode (urlencode) + 2.61 URL Decode (urldecode)
- 2.62 Add a New User (useradd) + 2.62 URL Encode (urlencode)
- 2.63 Delete a user (userdel) + 2.63 Add a New User (useradd)
- 2.64 Wait for Microseconds (usleep) + 2.64 Delete a user (userdel)
- 2.65 Get File Via HTTP (wget) + 2.65 Wait for Microseconds (usleep)
- 2.66 Hexadecimal Dump of Memory (xd) + 2.66 Get File Via HTTP (wget) + + + +
+ + 2.67 Hexadecimal Dump of Memory (xd) @@ -1681,13 +1687,6 @@ hexdump <file or device> Dump data in hexadecimal format from a file or character device.

- -
- - - - - + + + + + - + @@ -5165,10 +5194,10 @@ xxd -i romfs_img >nsh_romfsimg.h
  • CONFIG_NSH_ROMFSETC
  • CONFIG_NSH_ARCHROMFS
  • CONFIG_NSH_ROMFSMOUNTPT
  • +
  • CONFIG_NSH_ROMFSSECTSIZE
  • @@ -1937,7 +1936,32 @@ losetup d <dev-path> + +
    -

    2.30 List Directory Contents (ls)

    +

    2.30 List to a File or Directory (ln)

    +
    + +

    Command Syntax:

    +
      +link [-s] <target> <link>
      +
    +

    + Synopsis. + The link command will create a new symbolic link at <link> for the existing file or directory, <target>. + This implementation is simplied for use with NuttX in these ways: +

    +
      +
    • Links may be created only within the NuttX top-level, pseudo file system. + No file system currently supported by NuttX provides symbolic links.
    • +
    • For the same reason, only soft links are implemented.
    • +
    • File privileges are ignored.
    • +
    • c_time is not updated.
    • +
    + + + +
    +

    2.31 List Directory Contents (ls)

    @@ -1975,7 +1999,7 @@ ls [-lRs] <dir-path>
    -

    2.31 Show information about installed OS modules (lsmod)

    +

    2.32 Show information about installed OS modules (lsmod)

    @@ -2008,7 +2032,7 @@ mydriver 20404659 20404625 0 20404580 552 204047a8 0
    -

    2.32 Calculate MD5 (md5)

    +

    2.33 Calculate MD5 (md5)

    @@ -2025,7 +2049,7 @@ md5 [-f] <string or filepath>
    -

    2.33 Access Memory (mb, mh, and mw)

    +

    2.34 Access Memory (mb, mh, and mw)

    @@ -2079,7 +2103,7 @@ nsh>
    -

    2.34 Show Current Tasks and Threads (ps)

    +

    2.35 Show Current Tasks and Threads (ps)

    @@ -2113,7 +2137,7 @@ nsh> mount -t procfs /proc
    -

    2.35 Create a Directory (mkdir)

    +

    2.36 Create a Directory (mkdir)

    @@ -2148,7 +2172,7 @@ nsh>
    -

    2.36 Create a FAT Filesystem (mkfatfs)

    +

    2.37 Create a FAT Filesystem (mkfatfs)

    @@ -2173,7 +2197,7 @@ mkfatfs [-F <fatsize>] <block-driver>
    -

    2.37 Create a FIFO (mkfifo)

    +

    2.38 Create a FIFO (mkfifo)

    @@ -2211,7 +2235,7 @@ nsh>
    -

    2.38 Create a RAMDISK (mkrd)

    +

    2.39 Create a RAMDISK (mkrd)

    @@ -2262,7 +2286,7 @@ nsh>
    -

    2.39 Mount a File System (mount)

    +

    2.40 Mount a File System (mount)

    @@ -2341,7 +2365,7 @@ nsh> mount
    -

    2.40 Rename a File (mv)

    +

    2.41 Rename a File (mv)

    @@ -2359,7 +2383,7 @@ mv <old-path> <new-path>
    -

    2.41 Mount an NFS file system (nfsmount)

    +

    2.42 Mount an NFS file system (nfsmount)

    @@ -2378,7 +2402,7 @@ nfsmount <server-address> <mount-point> <remote-path>
    -

    2.42 Lookup a network address (nslookup)

    +

    2.43 Lookup a network address (nslookup)

    @@ -2395,7 +2419,7 @@ nslookup <host-name>
    -

    2.43 Change a User's Password (passwd)

    +

    2.44 Change a User's Password (passwd)

    @@ -2412,7 +2436,7 @@ passwd <username> <password>
    -

    2.44 Check Network Peer (ping/ping6)

    +

    2.45 Check Network Peer (ping/ping6)

    @@ -2449,7 +2473,7 @@ nsh>
    -

    2.45 Shut the system down (poweroff)

    +

    2.46 Shut the system down (poweroff)

    @@ -2471,7 +2495,7 @@ poweroff
    -

    2.46 Send File Via TFTP (put)

    +

    2.47 Send File Via TFTP (put)

    @@ -2506,7 +2530,7 @@ put [-b|-n] [-f <remote-path>] -h <ip-address> <local-path>
    -

    2.47 Show Current Working Directory (pwd)

    +

    2.48 Show Current Working Directory (pwd)

    @@ -2536,7 +2560,7 @@ nsh>
    -

    2.48 Reboot the system (reboot)

    +

    2.49 Reboot the system (reboot)

    @@ -2558,7 +2582,7 @@ reboot
    -

    2.49 Remove a File (rm)

    +

    2.50 Remove a File (rm)

    @@ -2592,7 +2616,7 @@ nsh>
    -

    2.50 Remove a Directory (rmdir)

    +

    2.51 Remove a Directory (rmdir)

    @@ -2627,7 +2651,7 @@ nsh>
    -

    2.51 Remove on OS Module (rmmod)

    +

    2.52 Remove on OS Module (rmmod)

    @@ -2655,7 +2679,7 @@ nsh>
    -

    2.52 Set an Environment Variable (set)

    +

    2.53 Set an Environment Variable (set)

    @@ -2681,7 +2705,7 @@ nsh>
    -

    2.53 Execute an NSH Script (sh)

    +

    2.54 Execute an NSH Script (sh)

    @@ -2700,7 +2724,7 @@ sh <script-path>
    -

    2.54 Shut the system down (shutdown)

    +

    2.55 Shut the system down (shutdown)

    @@ -2721,7 +2745,7 @@ shutdown [--reboot]
    -

    2.55 Wait for Seconds (sleep)

    +

    2.56 Wait for Seconds (sleep)

    @@ -2738,7 +2762,7 @@ sleep <sec>
    -

    2.56 Time execution of another command (time)

    +

    2.57 Time execution of another command (time)

    @@ -2797,7 +2821,7 @@ nsh>
    -

    2.57 Unmount a File System (umount)

    +

    2.58 Unmount a File System (umount)

    @@ -2827,7 +2851,7 @@ nsh>
    -

    2.58 Print system information (uname)

    +

    2.59 Print system information (uname)

    @@ -2894,7 +2918,7 @@ uname [-a | -imnoprsv]
    -

    2.59 Unset an Environment Variable (unset)

    +

    2.60 Unset an Environment Variable (unset)

    @@ -2920,7 +2944,7 @@ nsh>
    -

    2.60 URL Decode (urldecode)

    +

    2.61 URL Decode (urldecode)

    @@ -2937,7 +2961,7 @@ urldecode [-f] <string or filepath>
    -

    2.61 URL Encode (urlencode)

    +

    2.62 URL Encode (urlencode)

    @@ -2954,7 +2978,7 @@ urlencode [-f] <string or filepath>
    -

    2.62 Add a New User (useradd)

    +

    2.63 Add a New User (useradd)

    @@ -2971,7 +2995,7 @@ useradd <username> <password>
    -

    2.63 Delete a user (userdel)

    +

    2.64 Delete a user (userdel)

    @@ -2988,7 +3012,7 @@ userdel <username>
    -

    2.64 Wait for Microseconds (usleep)

    +

    2.65 Wait for Microseconds (usleep)

    @@ -3005,7 +3029,7 @@ usleep <usec>
    -

    2.65 Get File Via HTTP (wget)

    +

    2.66 Get File Via HTTP (wget)

    @@ -3032,7 +3056,7 @@ wget [-o <local-path>] <url>
    -

    2.66 Hexadecimal Dump of Memory (xd)

    +

    2.67 Hexadecimal Dump of Memory (xd)

    @@ -3241,10 +3265,15 @@ nsh>
    !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_DEV_LOOP CONFIG_NSH_DISABLE_LOSETUP
    lnCONFIG_NFILE_DESCRIPTORS > 0CONFIG_NSH_DISABLE_LL
    ls CONFIG_NFILE_DESCRIPTORS > 0CONFIG_NSH_DISABLE_LSCONFIG_NSH_DISABLE_LS && CONFIG_PSEUDOFS_SOFTLINKS
    lsmod
      -
    • CONFIG_NSH_ROMFSSECTSIZE
    • CONFIG_NSH_STRERROR
    • CONFIG_NSH_TELNET
    • CONFIG_NSH_TMPDIR
    • @@ -5218,6 +5247,7 @@ xxd -i romfs_img >nsh_romfsimg.h
    • insmod
    • kill
    • losetup
    • +
    • ln
    • ls
    • mb
    • Login
    • diff --git a/arch/sim/src/nuttx-names.dat b/arch/sim/src/nuttx-names.dat index f1373f1d9c1..bfede730667 100644 --- a/arch/sim/src/nuttx-names.dat +++ b/arch/sim/src/nuttx-names.dat @@ -32,6 +32,7 @@ gettimeofday NXgettimeofday ioctl NXioctl isatty NXisatty kill NXkill +link NXlink listen NXlisten lseek NXlseek mallinfo NXmallinfo diff --git a/fs/Makefile b/fs/Makefile index 5ef45f84ee2..6ab682d28f2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -1,7 +1,7 @@ ############################################################################ # fs/Makefile # -# Copyright (C) 2007, 2008, 2011-2014, 2016 Gregory Nutt. All rights reserved. +# Copyright (C) 2007, 2008, 2011-2014, 2016-2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 9b5e6911afb..9209da62983 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -43,10 +43,6 @@ ifneq ($(CONFIG_NSOCKET_DESCRIPTORS),0) CSRCS += fs_close.c fs_read.c fs_write.c fs_ioctl.c -ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) -CSRCS += fs_softlink.c -endif - # Stream support ifneq ($(CONFIG_NFILE_STREAMS),0) @@ -91,7 +87,7 @@ endif CSRCS += fs_pread.c fs_pwrite.c ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) -CSRCS += fs_softlink.c +CSRCS += fs_link.c endif # Stream support diff --git a/fs/vfs/fs_softlink.c b/fs/vfs/fs_link.c similarity index 90% rename from fs/vfs/fs_softlink.c rename to fs/vfs/fs_link.c index b40a5ea9727..285db3bae8c 100644 --- a/fs/vfs/fs_softlink.c +++ b/fs/vfs/fs_link.c @@ -1,5 +1,5 @@ /**************************************************************************** - * fs/vfs/fs_softlink.c + * fs/vfs/fs_link.c * * Copyright (C) 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -64,7 +65,7 @@ * * Description: * The link() function will create a new link (directory entry) for the - * existing file, path1. This implementation is simplied for use with + * existing file, path2. This implementation is simplied for use with * NuttX in these ways: * * - Links may be created only within the NuttX top-level, pseudo file @@ -90,21 +91,21 @@ int link(FAR const char *path1, FAR const char *path2) int errcode; int ret; - /* Both paths must be absolute. We need only check path2 here. path1 will + /* Both paths must be absolute. We need only check path1 here. path2 will * be checked by inode find. */ - if (path2 == NULL || *path2 != '/') + if (path1 == NULL || *path1 != '/') { errcode = EINVAL; goto errout; } - /* Check that no inode exists at the 'path2' and that the path up to 'path2' + /* Check that no inode exists at the 'path1' and that the path up to 'path1' * does not lie on a mounted volume. */ - inode = inode_find(path1, NULL); + inode = inode_find(path2, NULL); if (inode != NULL) { #ifndef CONFIG_DISABLE_MOUNTPOINT @@ -119,7 +120,7 @@ int link(FAR const char *path1, FAR const char *path2) else #endif { - /* A node already exists in the pseudofs at 'path2' */ + /* A node already exists in the pseudofs at 'path1' */ errcode = EEXIST; } @@ -133,9 +134,9 @@ int link(FAR const char *path1, FAR const char *path2) else { - /* Copy path2 */ + /* Copy path1 */ - FAR char *newpath2 = strdup(path2); + FAR char *newpath2 = strdup(path1); if (newpath2 == NULL) { errcode = ENOMEM; @@ -148,7 +149,7 @@ int link(FAR const char *path1, FAR const char *path2) */ inode_semtake(); - ret = inode_reserve(path1, &inode); + ret = inode_reserve(path2, &inode); inode_semgive(); if (ret < 0) diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 584ccef287f..955d1b2c111 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -328,7 +328,7 @@ union inode_ops_u FAR struct mqueue_inode_s *i_mqueue; /* POSIX message queue */ #endif #ifdef CONFIG_PSEUDOFS_SOFTLINKS - FAR char *i_link; /* Full path to link */ + FAR char *i_link; /* Full path to link target */ #endif }; diff --git a/include/sys/syscall.h b/include/sys/syscall.h index eb53fdf9787..ac1dde570bf 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -323,11 +323,18 @@ # define SYS_statfs (__SYS_filedesc+12) # define SYS_telldir (__SYS_filedesc+13) -# if defined(CONFIG_PIPES) && CONFIG_DEV_PIPE_SIZE > 0 -# define SYS_pipe2 (__SYS_filedesc+14) -# define __SYS_mkfifo2 (__SYS_filedesc+15) +# if defined(CONFIG_PSEUDOFS_SOFTLINKS) +# define SYS_link (__SYS_filedesc+14) +# define __SYS_pipes (__SYS_filedesc+15) # else -# define __SYS_mkfifo2 (__SYS_filedesc+14) +# define __SYS_pipes (__SYS_filedesc+14) +# endif + +# if defined(CONFIG_PIPES) && CONFIG_DEV_PIPE_SIZE > 0 +# define SYS_pipe2 (__SYS_pipes+0) +# define __SYS_mkfifo2 (__SYS_pipes+1) +# else +# define __SYS_mkfifo2 (__SYS_pipes+0) # endif # if defined(CONFIG_PIPES) && CONFIG_DEV_FIFO_SIZE > 0 diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 1b6917d5f38..d8ff96cf034 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -32,6 +32,7 @@ "insmod","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR const char *","FAR const char *" "ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long" "kill","signal.h","!defined(CONFIG_DISABLE_SIGNALS)","int","pid_t","int" +"link","unistd.h","defined(CONFIG_PSEUDOFS_SOFTLINKS)","int","FAR const char *","FAR const char *" "listen","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int" "lseek","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0","off_t","int","off_t","int" "mkdir","sys/stat.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*","mode_t" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index f8286ca6b1d..b302a928296 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -232,6 +232,10 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) SYSCALL_LOOKUP(statfs, 2, STUB_statfs) SYSCALL_LOOKUP(telldir, 1, STUB_telldir) +# if defined(CONFIG_PSEUDOFS_SOFTLINKS) + SYSCALL_LOOKUP(link, 2, STUB_link) +# endif + # if defined(CONFIG_PIPES) && CONFIG_DEV_PIPE_SIZE > 0 SYSCALL_LOOKUP(pipe2, 2, STUB_pipe2) # endif diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index 59c4515ac40..950553c7425 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -238,6 +238,8 @@ uintptr_t STUB_stat(int nbr, uintptr_t parm1, uintptr_t parm2); uintptr_t STUB_statfs(int nbr, uintptr_t parm1, uintptr_t parm2); uintptr_t STUB_telldir(int nbr, uintptr_t parm1); +uintptr_t STUB_link(int nbr, uintptr_t parm1, uintptr_t parm2); + uintptr_t STUB_pipe2(int nbr, uintptr_t parm1, uintptr_t parm2); uintptr_t STUB_mkfifo2(int nbr, uintptr_t parm1, uintptr_t parm2, uintptr_t parm3); From d833144869fba546653e5d0d19dbcb72907fc0f2 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 2 Feb 2017 19:37:58 -0600 Subject: [PATCH 5/7] Soft Links: Fix several issues in initial testing --- fs/inode/fs_inode.c | 90 +++++++++++++++++++++++++++++++++++---- fs/inode/fs_inoderemove.c | 7 ++- 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index 1da4069c293..1626dafa231 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -186,6 +186,7 @@ static inline FAR struct inode * _inode_dereference(FAR struct inode *node, FAR struct inode **peer, FAR struct inode **parent, FAR const char **relpath) { + FAR const char *copy; unsigned int count = 0; /* An infinite loop is avoided only by the loop count. @@ -196,9 +197,14 @@ _inode_dereference(FAR struct inode *node, FAR struct inode **peer, while (node != NULL && INODE_IS_SOFTLINK(node)) { - node = inode_search_nofollow((FAR const char **)&node->u.i_link, - peer, parent, relpath); - if (++count > SYMLOOP_MAX) + /* Careful: inode_search_nofollow overwrites the input string pointer */ + + copy = (FAR const char *)node->u.i_link; + + /* Now, look-up the inode associated with the target path */ + + node = inode_search_nofollow(©, peer, parent, relpath); + if (node == NULL && ++count > SYMLOOP_MAX) { return NULL; } @@ -348,6 +354,20 @@ FAR struct inode *inode_search(FAR const char **path, FAR struct inode *node = g_root_inode; FAR struct inode *left = NULL; FAR struct inode *above = NULL; +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + FAR struct inode *newnode; +#endif + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* Handle the case were the root node is a symbolic link */ + +#warning Missing logic +#endif + + /* Traverse the pseudo file system node tree until either (1) all nodes + * have been examined without finding the matching node, or (2) the + * matching node is found. + */ while (node != NULL) { @@ -383,13 +403,32 @@ FAR struct inode *inode_search(FAR const char **path, FAR const char *nextname = inode_nextname(name); if (*nextname != '\0') { - node = _inode_dereference(node, NULL, &above, relpath); - if (node == NULL) + newnode = _inode_dereference(node, NULL, &above, relpath); + if (newnode == NULL) { + /* Probably means that the node is a symbolic link, but + * that the target of the symbolic link does not exist. + */ + break; } + else if (newnode != node) + { + /* The node was a valid symbolic link and we have jumped to a + * different, spot in the the pseudo file system tree. Reset + * everything and continue looking at the next level "down" + * from that new spot in the tree. + */ + + above = newnode; + left = NULL; + node = newnode->i_child; + continue; + } } #endif + /* Continue looking to the left */ + left = node; node = node->i_peer; } @@ -429,7 +468,7 @@ FAR struct inode *inode_search(FAR const char **path, } else { - /* More to go.. */ + /* More nodes to be examined in the path... */ #ifdef CONFIG_PSEUDOFS_SOFTLINKS /* If this intermediate inode in the is a soft link, then (1) @@ -438,13 +477,46 @@ FAR struct inode *inode_search(FAR const char **path, * continue searching with that inode instead. */ - node = _inode_dereference(node, NULL, NULL, relpath); - if (node == NULL) + newnode = _inode_dereference(node, NULL, NULL, relpath); + if (newnode == NULL) { + /* Probably means that the node is a symbolic link, but + * that the target of the symbolic link does not exist. + */ + break; } -#endif + else if (newnode != node) + { + /* The node was a valid symbolic link and we have jumped to a + * different, spot in the the pseudo file system tree. Reset + * everything and continue looking to the right (if possible) + * otherwise at the next level "down" from that new spot in + * the tree. + */ + if (newnode->i_peer != NULL) + { + above = NULL; /* REVISIT: This can't be right */ + left = newnode; + node = newnode->i_peer; + + /* Did the symbolic link take us to a mountpoint? */ + + if (INODE_IS_MOUNTPT(newnode)) + { + /* Yes.. return the mountpoint information */ + + if (relpath) + { + *relpath = name; + } + + break; + } + } + } +#endif /* Keep looking at the next level "down" */ above = node; diff --git a/fs/inode/fs_inoderemove.c b/fs/inode/fs_inoderemove.c index 8f454f1d584..6df048dbbe0 100644 --- a/fs/inode/fs_inoderemove.c +++ b/fs/inode/fs_inoderemove.c @@ -58,6 +58,11 @@ * path refers to. This is normally done in preparation to removing or * moving an inode. * + * In symbolic links in the pseduo file system are enabled, then this + * logic will follow the symbolic links up until the terminal node. Then + * that link in removed. So if this the terminal node is a symbolic link, + * the symbolic link node will be removed, not the target of the link. + * * Assumptions/Limitations: * The caller must hold the inode semaphore * @@ -79,7 +84,7 @@ FAR struct inode *inode_unlink(FAR const char *path) /* Find the node to unlink */ - node = inode_search(&name, &peer, &parent, (const char **)NULL); + node = inode_search_nofollow(&name, &peer, &parent, (const char **)NULL); if (node) { /* If peer is non-null, then remove the node from the right of From 372e399bbc7168a009c334925250becadeb9fc2c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 3 Feb 2017 07:36:25 -0600 Subject: [PATCH 6/7] Fix a typo --- fs/vfs/Make.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 9209da62983..c768b1819ab 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -43,7 +43,7 @@ ifneq ($(CONFIG_NSOCKET_DESCRIPTORS),0) CSRCS += fs_close.c fs_read.c fs_write.c fs_ioctl.c -# Stream support +# Support for network access using streams ifneq ($(CONFIG_NFILE_STREAMS),0) CSRCS += fs_fdopen.c From 741a221fdbf4c53793a7121bf824980c7f62d1ea Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 3 Feb 2017 09:24:43 -0600 Subject: [PATCH 7/7] Soft link: make SOFTLINK configuration EXPERIMENTAL. There are still issues. --- fs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/Kconfig b/fs/Kconfig index 05ab5daea93..1bd8d5f945f 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -43,7 +43,7 @@ config DISABLE_PSEUDOFS_OPERATIONS config PSEUDOFS_SOFTLINKS bool "Pseudo-filesystem soft links" default n - depends on !DISABLE_PSEUDOFS_OPERATIONS + depends on !DISABLE_PSEUDOFS_OPERATIONSi && EXPERIMENTAL ---help--- Enable support for soft links in the pseudeo file system. Soft links are not supported within mounted volumes by any NuttX file