Finish implementation of soft links.

This commit is contained in:
Gregory Nutt 2017-02-02 13:01:21 -06:00
parent 92305e400a
commit bdc002fadc
7 changed files with 222 additions and 24 deletions

View File

@ -40,6 +40,7 @@
#include <nuttx/config.h>
#include <assert.h>
#include <limits.h>
#include <semaphore.h>
#include <assert.h>
#include <errno.h>
@ -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
*

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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();

View File

@ -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

View File

@ -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.