lsmod |
@@ -5165,10 +5194,10 @@ xxd -i romfs_img >nsh_romfsimg.h
CONFIG_NSH_ROMFSETC
CONFIG_NSH_ARCHROMFS
CONFIG_NSH_ROMFSMOUNTPT
+ CONFIG_NSH_ROMFSSECTSIZE
- 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/Kconfig b/fs/Kconfig
index 603d9a51152..1bd8d5f945f 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -40,6 +40,18 @@ 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 n
+ 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
+ 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/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/inode/fs_inode.c b/fs/inode/fs_inode.c
index 3658ad5e44f..1626dafa231 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
@@ -40,7 +40,9 @@
#include
#include
+#include
#include
+#include
#include
#include
@@ -166,6 +168,52 @@ 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)
+{
+ FAR const char *copy;
+ 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))
+ {
+ /* 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;
+ }
+ }
+
+ return node;
+}
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -274,28 +322,54 @@ 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;
+#ifdef CONFIG_PSEUDOFS_SOFTLINKS
+ FAR struct inode *newnode;
+#endif
- while (node)
+#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)
{
int result = _inode_compare(name, node);
@@ -318,6 +392,43 @@ 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')
+ {
+ 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;
}
@@ -326,15 +437,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
@@ -345,15 +456,72 @@ 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 nodes to be examined in the path... */
+
+#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.
+ */
+
+ 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;
+ }
+ 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;
left = NULL;
- node = node->i_child;
+ node = node->i_child;
}
}
}
@@ -387,6 +555,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
*
@@ -401,8 +596,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) && node->u.i_link != NULL)
+ {
+ kmm_free(node->u.i_link);
+ }
+#endif
+
kmm_free(node);
}
}
diff --git a/fs/inode/fs_inodefind.c b/fs/inode/fs_inodefind.c
index 37ca35bf900..b5339c9b863 100644
--- a/fs/inode/fs_inodefind.c
+++ b/fs/inode/fs_inodefind.c
@@ -49,12 +49,16 @@
****************************************************************************/
/****************************************************************************
- * 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)
@@ -82,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,
+ FAR const 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/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
diff --git a/fs/inode/inode.h b/fs/inode/inode.h
index f909d74ef17..529642bfa71 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,
+ FAR const char **relpath);
+#else
+# define inode_find_nofollow(p,r) inode_find(p,r)
+#endif
/****************************************************************************
* Name: inode_addref
diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs
index 645e23f97e4..c768b1819ab 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
@@ -86,6 +86,10 @@ endif
CSRCS += fs_pread.c fs_pwrite.c
+ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0)
+CSRCS += fs_link.c
+endif
+
# Stream support
ifneq ($(CONFIG_NFILE_STREAMS),0)
diff --git a/fs/vfs/fs_link.c b/fs/vfs/fs_link.c
new file mode 100644
index 00000000000..285db3bae8c
--- /dev/null
+++ b/fs/vfs/fs_link.c
@@ -0,0 +1,180 @@
+/****************************************************************************
+ * fs/vfs/fs_link.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
+
+#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, path2. 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;
+
+ /* Both paths must be absolute. We need only check path1 here. path2 will
+ * be checked by inode find.
+ */
+
+ if (path1 == NULL || *path1 != '/')
+ {
+ errcode = EINVAL;
+ goto errout;
+ }
+
+ /* 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(path2, NULL);
+ if (inode != NULL)
+ {
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+ /* Check if the inode is a mountpoint. */
+
+ if (INODE_IS_MOUNTPT(inode))
+ {
+ /* Symbolic links within the mounted volume are not supported */
+
+ errcode = ENOSYS;
+ }
+ else
+#endif
+ {
+ /* A node already exists in the pseudofs at 'path1' */
+
+ errcode = 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 path1 */
+
+ FAR char *newpath2 = strdup(path1);
+ 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(path2, &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/fs/vfs/fs_unlink.c b/fs/vfs/fs_unlink.c
index 2cc6c23a7d7..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,11 +126,11 @@ 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 unlink should remove the node.
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 cc01a643507..955d1b2c111 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -76,6 +76,7 @@
#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 */
@@ -90,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)
@@ -105,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 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)
@@ -313,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 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/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 */
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);
|