Finish implementation of soft links.
This commit is contained in:
parent
92305e400a
commit
bdc002fadc
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user