This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit a0adad660264881acc1f83d901bf7f2f3a2f81bd
Author: Abhishek Mishra <[email protected]>
AuthorDate: Wed Aug 19 08:07:17 2026 +0000

    fs: start absolute lookups at the jail root
    
    Prepare paths in inode_search_setup(): prepend tg_root, canonicalize
    with a jail-floor dst_min, then walk from g_root_inode. Replace
    SETUP_SEARCH / RELEASE_SEARCH with inode_search_setup() /
    inode_search_release().
    
    Signed-off-by: Abhishek Mishra <[email protected]>
---
 fs/driver/fs_findblockdriver.c |  17 +-
 fs/driver/fs_finddriver.c      |  14 +-
 fs/driver/fs_findmtddriver.c   |  17 +-
 fs/event/event_open.c          |  14 +-
 fs/fat/fs_fat32attrib.c        |  16 +-
 fs/inode/fs_inodefind.c        |  14 +-
 fs/inode/fs_inoderemove.c      |  10 +-
 fs/inode/fs_inodereserve.c     |  10 +-
 fs/inode/fs_inodesearch.c      | 402 ++++++++++++++++++++++++-----------------
 fs/inode/inode.h               |  65 ++++---
 fs/littlefs/lfs_vfs.c          |   3 +
 fs/mount/fs_automount.c        |  16 +-
 fs/mount/fs_mount.c            |  31 ++--
 fs/mount/fs_umount2.c          |  13 +-
 fs/mqueue/mq_open.c            |  31 ++--
 fs/mqueue/mq_unlink.c          |  14 +-
 fs/partition/fs_partition.c    |   2 +
 fs/semaphore/sem_open.c        |  14 +-
 fs/semaphore/sem_unlink.c      |  14 +-
 fs/shm/shm_open.c              |  24 +--
 fs/shm/shm_unlink.c            |  16 +-
 fs/unionfs/fs_unionfs.c        |  13 +-
 fs/vfs/fs_chstat.c             |  11 +-
 fs/vfs/fs_close.c              |   1 +
 fs/vfs/fs_link.c               |  50 ++---
 fs/vfs/fs_mkdir.c              |  31 ++--
 fs/vfs/fs_open.c               |  17 +-
 fs/vfs/fs_readlink.c           |  27 ++-
 fs/vfs/fs_rename.c             |  66 ++++---
 fs/vfs/fs_rmdir.c              |  37 ++--
 fs/vfs/fs_stat.c               |  11 +-
 fs/vfs/fs_statfs.c             |  13 +-
 fs/vfs/fs_symlink.c            |  35 ++--
 fs/vfs/fs_unlink.c             |  15 +-
 34 files changed, 604 insertions(+), 480 deletions(-)

diff --git a/fs/driver/fs_findblockdriver.c b/fs/driver/fs_findblockdriver.c
index 656bdc7a866..abc6ac54401 100644
--- a/fs/driver/fs_findblockdriver.c
+++ b/fs/driver/fs_findblockdriver.c
@@ -77,20 +77,19 @@ int find_blockdriver(FAR const char *pathname, int 
mountflags,
 
   /* Find the inode registered with this pathname */
 
-  SETUP_SEARCH(&desc, pathname, false);
+  ret = inode_search_setup(&desc, pathname, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       ferr("ERROR: Failed to find %s\n", pathname);
-      ret = -ENOENT;
       goto errout_with_search;
     }
 
-  /* Get the search results */
-
-  inode = desc.node;
-
   /* Verify that the inode is a block driver. */
 
   if (!INODE_IS_BLOCK(inode))
@@ -121,12 +120,12 @@ int find_blockdriver(FAR const char *pathname, int 
mountflags,
     }
 
   *ppinode = inode;
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return OK;
 
 errout_with_inode:
   inode_release(inode);
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
diff --git a/fs/driver/fs_finddriver.c b/fs/driver/fs_finddriver.c
index f2724ba43d7..4f071510a3c 100644
--- a/fs/driver/fs_finddriver.c
+++ b/fs/driver/fs_finddriver.c
@@ -50,29 +50,33 @@
 FAR void *find_driver(FAR const char *pathname)
 {
   struct inode_search_s desc;
+  FAR struct inode *inode;
   FAR void *drvr = NULL;
 
   DEBUGASSERT(pathname != NULL);
 
   /* Find the inode registered with this pathname */
 
-  SETUP_SEARCH(&desc, pathname, false);
+  if (inode_search_setup(&desc, pathname, false) < 0)
+    {
+      return NULL;
+    }
 
   /* Get the search results */
 
   inode_lock();
-  if (inode_find(&desc) < 0)
+  if (inode_find(&desc, &inode) < 0)
     {
       ferr("ERROR: Failed to find %s\n", pathname);
     }
   else
     {
-      drvr = desc.node->i_private;
-      inode_release(desc.node);
+      drvr = inode->i_private;
+      inode_release(inode);
     }
 
   inode_unlock();
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 
   return drvr;
 }
diff --git a/fs/driver/fs_findmtddriver.c b/fs/driver/fs_findmtddriver.c
index e20e490acef..df3b0fe679e 100644
--- a/fs/driver/fs_findmtddriver.c
+++ b/fs/driver/fs_findmtddriver.c
@@ -70,20 +70,19 @@ int find_mtddriver(FAR const char *pathname, FAR struct 
inode **ppinode)
 
   /* Find the inode registered with this pathname */
 
-  SETUP_SEARCH(&desc, pathname, false);
+  ret = inode_search_setup(&desc, pathname, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       ferr("ERROR: Failed to find %s\n", pathname);
-      ret = -ENOENT;
       goto errout_with_search;
     }
 
-  /* Get the search results */
-
-  inode = desc.node;
-
   /* Verify that the inode is a block driver. */
 
   if (!INODE_IS_MTD(inode))
@@ -98,14 +97,14 @@ int find_mtddriver(FAR const char *pathname, FAR struct 
inode **ppinode)
   DEBUGASSERT(inode->u.i_mtd != NULL);
 
   *ppinode = inode;
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return OK;
 
 errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/event/event_open.c b/fs/event/event_open.c
index 6781d055029..f6d40d7b953 100644
--- a/fs/event/event_open.c
+++ b/fs/event/event_open.c
@@ -102,15 +102,17 @@ int nxevent_open(FAR nxevent_t **event, FAR const char 
*name,
    * will have incremented the reference count on the inode.
    */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret >= 0)
     {
       /* Something exists at this path.  Get the search results */
 
-      inode = desc.node;
-
       /* Verify that the inode is a event group */
 
       if (!INODE_IS_NAMEDEVENT(inode))
@@ -206,7 +208,7 @@ int nxevent_open(FAR nxevent_t **event, FAR const char 
*name,
       *event = &nevent->ne_event;
     }
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_open(fullpath, oflags);
 #endif
@@ -216,6 +218,6 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
diff --git a/fs/fat/fs_fat32attrib.c b/fs/fat/fs_fat32attrib.c
index 66880492234..fb2dbcc0b4d 100644
--- a/fs/fat/fs_fat32attrib.c
+++ b/fs/fat/fs_fat32attrib.c
@@ -59,9 +59,13 @@ static int fat_attrib(const char *path, fat_attrib_t 
*retattrib,
 
   /* Find the inode for this file */
 
-  SETUP_SEARCH(&desc, path, false);
+  ret = inode_search_setup(&desc, path, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* There is no mountpoint that includes in this path */
@@ -69,10 +73,6 @@ static int fat_attrib(const char *path, fat_attrib_t 
*retattrib,
       goto errout;
     }
 
-  /* Get the search results */
-
-  inode = desc.node;
-
   /* Verify that the inode is a valid mountpoint. */
 
   if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops || !inode->i_private)
@@ -154,7 +154,7 @@ static int fat_attrib(const char *path, fat_attrib_t 
*retattrib,
 
   nxmutex_unlock(&fs->fs_lock);
   inode_release(inode);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return OK;
 
 errout_with_lock:
@@ -164,7 +164,7 @@ errout_with_inode:
   inode_release(inode);
 
 errout:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/inode/fs_inodefind.c b/fs/inode/fs_inodefind.c
index 78cd426cf13..b975cf6fcaa 100644
--- a/fs/inode/fs_inodefind.c
+++ b/fs/inode/fs_inodefind.c
@@ -49,7 +49,7 @@
  *
  ****************************************************************************/
 
-int inode_find(FAR struct inode_search_s *desc)
+int inode_find(FAR struct inode_search_s *desc, FAR struct inode **inode)
 {
   int ret;
 
@@ -57,18 +57,22 @@ int inode_find(FAR struct inode_search_s *desc)
    * references on the node.
    */
 
+  if (inode == NULL)
+    {
+      return -EINVAL;
+    }
+
   inode_rlock();
-  ret = inode_search(desc);
+  ret = inode_search(desc, inode);
   if (ret >= 0)
     {
       /* Found it */
 
-      FAR struct inode *inode = desc->node;
-      DEBUGASSERT(inode != NULL);
+      DEBUGASSERT(*inode != NULL);
 
       /* Increment the reference count on the inode */
 
-      atomic_add(&inode->i_crefs, 1);
+      atomic_add(&(*inode)->i_crefs, 1);
     }
 
   inode_runlock();
diff --git a/fs/inode/fs_inoderemove.c b/fs/inode/fs_inoderemove.c
index 064d4a7ccfe..921244bcb80 100644
--- a/fs/inode/fs_inoderemove.c
+++ b/fs/inode/fs_inoderemove.c
@@ -71,12 +71,14 @@ static FAR struct inode *inode_unlink(FAR const char *path)
 
   /* Find the node to unlink */
 
-  SETUP_SEARCH(&desc, path, true);
+  if (inode_search_setup(&desc, path, true) < 0)
+    {
+      return NULL;
+    }
 
-  ret = inode_search(&desc);
+  ret = inode_search(&desc, &inode);
   if (ret >= 0)
     {
-      inode = desc.node;
       DEBUGASSERT(inode != NULL);
 
       if (desc.parent != NULL)
@@ -137,7 +139,7 @@ static FAR struct inode *inode_unlink(FAR const char *path)
     }
 
 errout:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return inode;
 }
 
diff --git a/fs/inode/fs_inodereserve.c b/fs/inode/fs_inodereserve.c
index 1b3c970e7e1..a547e28026e 100644
--- a/fs/inode/fs_inodereserve.c
+++ b/fs/inode/fs_inodereserve.c
@@ -208,9 +208,13 @@ int inode_reserve(FAR const char *path,
 
   /* Find the location to insert the new subtree */
 
-  SETUP_SEARCH(&desc, path, false);
+  ret = inode_search_setup(&desc, path, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_search(&desc);
+  ret = inode_search(&desc, NULL);
   if (ret != -ENOENT)
     {
       /* It is an error if the node already exists in the tree (or if it
@@ -291,6 +295,6 @@ int inode_reserve(FAR const char *path,
     }
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
diff --git a/fs/inode/fs_inodesearch.c b/fs/inode/fs_inodesearch.c
index fac611a7c8f..7862c21e15a 100644
--- a/fs/inode/fs_inodesearch.c
+++ b/fs/inode/fs_inodesearch.c
@@ -34,6 +34,8 @@
 #include <errno.h>
 
 #include <nuttx/fs/fs.h>
+#include <nuttx/sched.h>
+#include <nuttx/lib/lib.h>
 
 #include "inode/inode.h"
 
@@ -43,12 +45,11 @@
 
 static int _inode_compare(FAR const char *fname, FAR struct inode *inode);
 #ifdef CONFIG_FS_LINKS
-static int _inode_linktarget(FAR struct inode *inode,
+static int _inode_linktarget(FAR struct inode **inode,
                              FAR struct inode_search_s *desc);
 #endif
-static int _inode_search(FAR struct inode_search_s *desc);
 static FAR const char *_inode_getcwd(void);
-static int _inode_canonicalize(FAR char *path);
+static int _inode_canonicalize(FAR char *path, FAR char *dst_min);
 
 /****************************************************************************
  * Public Data
@@ -154,30 +155,34 @@ static int _inode_compare(FAR const char *fname, FAR 
struct inode *inode)
  ****************************************************************************/
 
 #ifdef CONFIG_FS_LINKS
-static int _inode_linktarget(FAR struct inode *inode,
+static int _inode_linktarget(FAR struct inode **inode,
                              FAR struct inode_search_s *desc)
 {
   unsigned int count = 0;
   bool save;
   int ret = -ENOENT;
 
-  DEBUGASSERT(desc != NULL && inode != NULL);
+  DEBUGASSERT(desc != NULL && inode != NULL && *inode != NULL);
 
   /* An infinite loop is avoided only by the loop count. */
 
   save = desc->nofollow;
-  while (INODE_IS_SOFTLINK(inode))
+  while (INODE_IS_SOFTLINK(*inode))
     {
-      FAR const char *link = (FAR const char *)inode->u.i_link;
+      FAR const char *link = (FAR const char *)(*inode)->u.i_link;
 
       /* Reset and reinitialize the search descriptor.  */
 
-      RELEASE_SEARCH(desc);
-      SETUP_SEARCH(desc, link, true);
+      inode_search_release(desc);
+      ret = inode_search_setup(desc, link, true);
+      if (ret < 0)
+        {
+          break;
+        }
 
       /* Look up inode associated with the target of the symbolic link */
 
-      ret = inode_search(desc);
+      ret = inode_search(desc, inode);
       if (ret < 0)
         {
           break;
@@ -193,8 +198,7 @@ static int _inode_linktarget(FAR struct inode *inode,
 
       /* Set up for the next time through the loop */
 
-      inode = desc->node;
-      DEBUGASSERT(inode != NULL);
+      DEBUGASSERT(*inode != NULL);
     }
 
   desc->nofollow = save;
@@ -229,13 +233,15 @@ static int _compute_path_depth(FAR const char *path)
  *
  * Description:
  *   Remove "." and ".." segments from an absolute path in-place.
- *   The path MUST start with '/'.  Returns -EINVAL if ".." attempts
- *   to ascend beyond the root directory, or -ENAMETOOLONG if the
- *   canonicalized result is >= PATH_MAX bytes.
+ *   The path MUST start with '/'.  'dst_min' is the lowest write
+ *   position ".." may pop to (path + 1 for the host root, or just
+ *   past the chroot prefix).  ".." that would ascend beyond that
+ *   floor is dropped.  Returns -ENAMETOOLONG if the canonicalized
+ *   result is >= PATH_MAX bytes.
  *
  ****************************************************************************/
 
-static int _inode_canonicalize(FAR char *path)
+static int _inode_canonicalize(FAR char *path, FAR char *dst_min)
 {
   /* Skip the initial '/' -- caller guarantees absolute path */
 
@@ -265,22 +271,18 @@ static int _inode_canonicalize(FAR char *path)
       if (src[0] == '.' && src[1] == '.' &&
           (src[2] == '/' || src[2] == '\0'))
         {
-          /* Cannot go above root */
-
-          if (dst <= path + 1)
+          if (dst > dst_min)
             {
-              return -EINVAL;
-            }
+              /* Remove trailing slash first */
 
-          /* Remove trailing slash first */
-
-          dst--;
+              dst--;
 
-          /* Scan backward to find the previous '/' */
+              /* Scan backward to find the previous '/' */
 
-          while (dst > path + 1 && *(dst - 1) != '/')
-            {
-              dst--;
+              while (dst > dst_min && *(dst - 1) != '/')
+                {
+                  dst--;
+                }
             }
 
           src += (src[2] == '/') ? 3 : 2;
@@ -358,108 +360,240 @@ static int _inode_checkpath(const char *path)
   return pathlen >= PATH_MAX ? -ENAMETOOLONG : OK;
 }
 
+#ifdef CONFIG_FS_CHROOT
 /****************************************************************************
- * Name: _inode_search
+ * Name: _inode_root_path
  *
  * Description:
- *   Find the inode associated with 'path' returning the inode references
- *   and references to its companion nodes.  This is the internal, common
- *   implementation of inode_search().
+ *   Return the calling group's jail prefix, or NULL if none is installed.
  *
- *   If a mountpoint is encountered in the search prior to encountering the
- *   terminal node, the search will terminate at the mountpoint inode.  That
- *   inode and the relative path from the mountpoint, 'relpath' will be
- *   returned.
+ ****************************************************************************/
+
+static FAR const char *_inode_root_path(void)
+{
+  FAR struct tcb_s *tcb = nxsched_self();
+
+  if (tcb != NULL && tcb->group != NULL)
+    {
+      return tcb->group->tg_root;
+    }
+
+  return NULL;
+}
+#endif
+
+/****************************************************************************
+ * Name: _inode_getcwd
  *
- *   If a soft link is encountered that is not the terminal node in the path,
- *   that link WILL be deferenced unconditionally.
+ * Description:
+ *   Return the current working directory
  *
- * Assumptions:
- *   The caller holds the g_inode_sem semaphore
+ ****************************************************************************/
+
+static FAR const char *_inode_getcwd(void)
+{
+  FAR const char *pwd = "";
+
+#ifndef CONFIG_DISABLE_ENVIRON
+  pwd = getenv("PWD");
+  if (pwd == NULL)
+    {
+      pwd = CONFIG_LIBC_HOMEDIR;
+    }
+#endif
+
+  return pwd;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: inode_search_release
+ *
+ * Description:
+ *   Release any buffer allocated by inode_search_setup().
  *
  ****************************************************************************/
 
-static int _inode_search(FAR struct inode_search_s *desc)
+void inode_search_release(FAR struct inode_search_s *desc)
 {
-  FAR const char   *name;
-  FAR struct inode *inode   = g_root_inode;
-  FAR struct inode *left    = NULL;
-  FAR struct inode *above   = NULL;
-  FAR const char   *relpath = NULL;
+  if (desc->buffer != NULL)
+    {
+      lib_put_tempbuffer(desc->buffer);
+      desc->buffer = NULL;
+    }
+}
+
+/****************************************************************************
+ * Name: inode_search_setup
+ *
+ * Description:
+ *   Initialize a search descriptor and make 'path' host-absolute: join
+ *   $PWD if it is relative, prepend the chroot jail if one is installed,
+ *   and canonicalize "." / "..".  On success desc->path points at
+ *   desc->buffer.
+ *
+ ****************************************************************************/
+
+int inode_search_setup(FAR struct inode_search_s *desc,
+                       FAR const char *path, bool nofollow)
+{
+  FAR const char *cwd = NULL;
+  FAR const char *root = NULL;
+  FAR char *dst_min;
+  size_t rootlen = 0;
+  size_t buflen;
   int ret;
 
-  ret = _inode_checkpath(desc->path);
+  desc->path     = path;
+  desc->peer     = NULL;
+  desc->parent   = NULL;
+  desc->relpath  = NULL;
+  desc->buffer   = NULL;
+  desc->nofollow = nofollow;
+
+  if (path == NULL)
+    {
+      return -EINVAL;
+    }
+
+  ret = _inode_checkpath(path);
   if (ret < 0)
     {
       return ret;
     }
 
-  /* Ensure we have a writable buffer for path manipulation */
-
-  if (desc->buffer == NULL)
+#ifdef CONFIG_FS_CHROOT
+  root = _inode_root_path();
+  if (root != NULL)
     {
-      FAR const char *cwd = NULL;
-      size_t buflen;
-
-      /* For a relative path the absolute form is "<cwd>/<path>".  That
-       * concatenation can exceed PATH_MAX even when the relative path
-       * itself is within PATH_MAX: a relative path of PATH_MAX-1 bytes
-       * is legal per pathconf(_PC_PATH_MAX), but the prefix added by the
-       * cwd pushes the uncanonicalized form past the limit.  Size the
-       * buffer to hold the full absolute form so that ".." segments are
-       * collapsed against the correct suffix; truncating first could
-       * drop the trailing component and let ".." collapse the path onto
-       * a directory (yielding the wrong errno, e.g. EISDIR, instead of
-       * resolving the file).  _inode_canonicalize() still rejects any
-       * result whose canonicalized length reaches PATH_MAX.
-       */
+      rootlen = strlen(root);
+    }
+#endif
 
-      if (*desc->path != '/')
-        {
-          cwd = _inode_getcwd();
-          buflen = strlen(cwd) + 1 + strlen(desc->path) + 1;
-        }
-      else
-        {
-          buflen = strlen(desc->path) + 1;
-        }
+  /* For a relative path the absolute form is "<cwd>/<path>".  That
+   * concatenation can exceed PATH_MAX even when the relative path
+   * itself is within PATH_MAX: a relative path of PATH_MAX-1 bytes
+   * is legal per pathconf(_PC_PATH_MAX), but the prefix added by the
+   * cwd pushes the uncanonicalized form past the limit.  Size the
+   * buffer to hold the full absolute form so that ".." segments are
+   * collapsed against the correct suffix; truncating first could
+   * drop the trailing component and let ".." collapse the path onto
+   * a directory (yielding the wrong errno, e.g. EISDIR, instead of
+   * resolving the file).  _inode_canonicalize() still rejects any
+   * result whose canonicalized length reaches PATH_MAX.
+   */
 
-      if (buflen < PATH_MAX)
-        {
-          buflen = PATH_MAX;
-        }
+  if (*path != '/')
+    {
+      cwd = _inode_getcwd();
+      buflen = strlen(cwd) + 1 + strlen(path) + 1;
+    }
+  else
+    {
+      buflen = strlen(path) + 1;
+    }
 
-      desc->buffer = lib_get_tempbuffer(buflen);
-      if (desc->buffer == NULL)
-        {
-          return -ENOMEM;
-        }
+  buflen += rootlen;
+  if (buflen < PATH_MAX)
+    {
+      buflen = PATH_MAX;
+    }
+
+  desc->buffer = lib_get_tempbuffer(buflen);
+  if (desc->buffer == NULL)
+    {
+      return -ENOMEM;
+    }
 
+  if (root != NULL)
+    {
       if (cwd != NULL)
         {
-          snprintf(desc->buffer, buflen, "%s/%s", cwd, desc->path);
+          snprintf(desc->buffer, buflen, "%s%s/%s", root, cwd, path);
         }
       else
         {
-          strlcpy(desc->buffer, desc->path, buflen);
+          snprintf(desc->buffer, buflen, "%s%s", root, path);
         }
-
-      desc->path = desc->buffer;
     }
+  else if (cwd != NULL)
+    {
+      snprintf(desc->buffer, buflen, "%s/%s", cwd, path);
+    }
+  else
+    {
+      strlcpy(desc->buffer, path, buflen);
+    }
+
+  desc->path = desc->buffer;
 
   /* Canonicalize the path to remove "." and ".." segments.  This ensures
    * that mountpoint relpath never contains ".." which most filesystems
-   * (tmpfs, romfs, etc.) cannot resolve.
+   * (tmpfs, romfs, etc.) cannot resolve.  When a jail is installed,
+   * dst_min keeps ".." from popping above tg_root.
    */
 
-  ret = _inode_canonicalize(desc->buffer);
+  dst_min = desc->buffer + 1;
+#ifdef CONFIG_FS_CHROOT
+  if (root != NULL)
+    {
+      dst_min = desc->buffer + rootlen;
+      if (rootlen > 0 && root[rootlen - 1] != '/')
+        {
+          dst_min++;
+        }
+    }
+#endif
+
+  ret = _inode_canonicalize(desc->buffer, dst_min);
   if (ret < 0)
     {
-      return ret;
+      inode_search_release(desc);
     }
 
+  return ret;
+}
+
+/****************************************************************************
+ * Name: inode_search
+ *
+ * Description:
+ *   Find the inode associated with 'path' returning the inode references
+ *   and references to its companion nodes.
+ *
+ *   If a mountpoint is encountered in the search prior to encountering the
+ *   terminal node, the search will terminate at the mountpoint inode.  That
+ *   inode and the relative path from the mountpoint, 'relpath' will be
+ *   returned.
+ *
+ *   inode_search will follow soft links in path leading up to the terminal
+ *   node.  Whether or no inode_search() will deference that terminal node
+ *   depends on the 'nofollow' input.
+ *
+ *   If a soft link is encountered that is not the terminal node in the path,
+ *   that link WILL be deferenced unconditionally.
+ *
+ * Assumptions:
+ *   The caller holds the g_inode_sem semaphore
+ *   The descriptor was initialized with inode_search_setup()
+ *
+ ****************************************************************************/
+
+int inode_search(FAR struct inode_search_s *desc, FAR struct inode **inodep)
+{
+  FAR const char   *name;
+  FAR struct inode *inode   = g_root_inode;
+  FAR struct inode *left    = NULL;
+  FAR struct inode *above   = NULL;
+  FAR const char   *relpath = NULL;
+  int ret = -ENOENT;
+
+  DEBUGASSERT(desc != NULL && desc->path != NULL);
+
   name = desc->path;
-  ret = -ENOENT;
 
   /* Traverse the pseudo file system node tree until either (1) all nodes
    * have been examined without finding the matching node, or (2) the
@@ -531,6 +665,7 @@ static int _inode_search(FAR struct inode_search_s *desc)
 
               if (INODE_IS_SOFTLINK(inode))
                 {
+                  FAR struct inode *newnode = inode;
                   int status;
 
                   /* If this intermediate inode in the is a soft link, then
@@ -539,7 +674,7 @@ static int _inode_search(FAR struct inode_search_s *desc)
                    * instead.
                    */
 
-                  status = _inode_linktarget(inode, desc);
+                  status = _inode_linktarget(&newnode, desc);
                   if (status < 0)
                     {
                       /* Probably means that the target of the symbolic link
@@ -551,8 +686,6 @@ static int _inode_search(FAR struct inode_search_s *desc)
                     }
                   else
                     {
-                      FAR struct inode *newnode = desc->node;
-
                       if (newnode != inode)
                         {
                           /* The node was a valid symbolic link and we have
@@ -642,85 +775,13 @@ static int _inode_search(FAR struct inode_search_s *desc)
    */
 
   desc->path    = name;
-  desc->node    = inode;
   desc->peer    = left;
   desc->parent  = above;
   desc->relpath = relpath;
-  return ret;
-}
-
-/****************************************************************************
- * Name: _inode_getcwd
- *
- * Description:
- *   Return the current working directory
- *
- ****************************************************************************/
-
-static FAR const char *_inode_getcwd(void)
-{
-  FAR const char *pwd = "";
-
-#ifndef CONFIG_DISABLE_ENVIRON
-  pwd = getenv("PWD");
-  if (pwd == NULL)
-    {
-      pwd = CONFIG_LIBC_HOMEDIR;
-    }
-#endif
-
-  return pwd;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: inode_search
- *
- * Description:
- *   Find the inode associated with 'path' returning the inode references
- *   and references to its companion nodes.
- *
- *   If a mountpoint is encountered in the search prior to encountering the
- *   terminal node, the search will terminate at the mountpoint inode.  That
- *   inode and the relative path from the mountpoint, 'relpath' will be
- *   returned.
- *
- *   inode_search will follow soft links in path leading up to the terminal
- *   node.  Whether or no inode_search() will deference that terminal node
- *   depends on the 'nofollow' input.
- *
- *   If a soft link is encountered that is not the terminal node in the path,
- *   that link WILL be deferenced unconditionally.
- *
- * Assumptions:
- *   The caller holds the g_inode_sem semaphore
- *
- ****************************************************************************/
-
-int inode_search(FAR struct inode_search_s *desc)
-{
-  int ret;
-
-  /* Perform the common _inode_search() logic.  This does everything except
-   * operations special operations that must be performed on the terminal
-   * node if node is a symbolic link.
-   */
-
-  DEBUGASSERT(desc != NULL && desc->path != NULL);
-
-  ret = _inode_search(desc);
 
 #ifdef CONFIG_FS_LINKS
   if (ret >= 0)
     {
-      FAR struct inode *inode;
-
-      /* Search completed successfully */
-
-      inode = desc->node;
       DEBUGASSERT(inode != NULL);
 
       /* Is the terminal node a softlink? Should we follow it? */
@@ -733,7 +794,7 @@ int inode_search(FAR struct inode_search_s *desc)
            * link target of the final symbolic link in the series.
            */
 
-          ret = _inode_linktarget(inode, desc);
+          ret = _inode_linktarget(&inode, desc);
           if (ret < 0)
             {
               /* The most likely cause for failure is that the target of the
@@ -749,12 +810,15 @@ int inode_search(FAR struct inode_search_s *desc)
 
           inode = inode->i_private;
           DEBUGASSERT(inode != NULL);
-
-          desc->node = inode;
         }
     }
 #endif
 
+  if (inodep != NULL)
+    {
+      *inodep = inode;
+    }
+
   return ret;
 }
 
diff --git a/fs/inode/inode.h b/fs/inode/inode.h
index 79a241e6dcc..eb015c7afb4 100644
--- a/fs/inode/inode.h
+++ b/fs/inode/inode.h
@@ -39,36 +39,11 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/sched.h>
 #include <nuttx/fs/fs.h>
-#include <nuttx/lib/lib.h>
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define SETUP_SEARCH(d,p,n) \
-  do \
-    { \
-      (d)->path     = (p); \
-      (d)->node     = NULL; \
-      (d)->peer     = NULL; \
-      (d)->parent   = NULL; \
-      (d)->relpath  = NULL; \
-      (d)->buffer   = NULL; \
-      (d)->nofollow = (n); \
-    } \
-  while (0)
-
-#define RELEASE_SEARCH(d) \
-  do \
-    { \
-      if ((d)->buffer != NULL) \
-        { \
-          lib_put_tempbuffer((d)->buffer); \
-          (d)->buffer  = NULL; \
-        } \
-    } \
-  while (0)
-
 #if CONFIG_FS_BACKTRACE > 0
 #  define FS_ADD_BACKTRACE(fd) \
      do \
@@ -110,8 +85,6 @@
  *
  *  path     - INPUT:  Path of inode to find
  *             OUTPUT: Residual part of path not traversed
- *  node     - INPUT:  (not used)
- *             OUTPUT: On success, holds the pointer to the inode found.
  *  peer     - INPUT:  (not used)
  *             OUTPUT: The inode to the "left" of the inode found.
  *  parent   - INPUT:  (not used)
@@ -138,7 +111,6 @@
 struct inode_search_s
 {
   FAR const char *path;      /* Path of inode to find */
-  FAR struct inode *node;    /* Pointer to the inode found */
   FAR struct inode *peer;    /* Node to the "left" for the found inode */
   FAR struct inode *parent;  /* Node "above" the found inode */
   FAR const char *relpath;   /* Relative path into the mountpoint */
@@ -243,12 +215,41 @@ void inode_runlock(void);
  *   If a soft link is encountered that is not the terminal node in the path,
  *   that link WILL be deferenced unconditionally.
  *
+ * Input Parameters:
+ *   desc  - Search descriptor initialized with inode_search_setup()
+ *   inode - OUTPUT: The found inode.  May be NULL if the caller only
+ *           cares about existence (e.g. inode_reserve).
+ *
  * Assumptions:
  *   The caller holds the g_inode_sem semaphore
+ *   The descriptor was initialized with inode_search_setup()
+ *
+ ****************************************************************************/
+
+int inode_search(FAR struct inode_search_s *desc, FAR struct inode **inode);
+
+/****************************************************************************
+ * Name: inode_search_setup
+ *
+ * Description:
+ *   Initialize a search descriptor and make 'path' host-absolute: join
+ *   $PWD if it is relative, prepend the chroot jail if one is installed,
+ *   and canonicalize "." / "..".
  *
  ****************************************************************************/
 
-int inode_search(FAR struct inode_search_s *desc);
+int inode_search_setup(FAR struct inode_search_s *desc,
+                       FAR const char *path, bool nofollow);
+
+/****************************************************************************
+ * Name: inode_search_release
+ *
+ * Description:
+ *   Release any buffer allocated by inode_search_setup().
+ *
+ ****************************************************************************/
+
+void inode_search_release(FAR struct inode_search_s *desc);
 
 /****************************************************************************
  * Name: inode_find
@@ -260,9 +261,13 @@ int inode_search(FAR struct inode_search_s *desc);
  *   difference between inode_find() and inode_search is that inode_find()
  *   will lock the inode tree and increment the reference count on the inode.
  *
+ * Input Parameters:
+ *   desc  - Search descriptor initialized with inode_search_setup()
+ *   inode - OUTPUT: The found inode.  Must not be NULL.
+ *
  ****************************************************************************/
 
-int inode_find(FAR struct inode_search_s *desc);
+int inode_find(FAR struct inode_search_s *desc, FAR struct inode **inode);
 
 /****************************************************************************
  * Name: inode_stat
diff --git a/fs/littlefs/lfs_vfs.c b/fs/littlefs/lfs_vfs.c
index e1853421c43..8cc3c0585e1 100644
--- a/fs/littlefs/lfs_vfs.c
+++ b/fs/littlefs/lfs_vfs.c
@@ -37,6 +37,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/fs/ioctl.h>
 #include <nuttx/kmalloc.h>
+#include <nuttx/lib/lib.h>
 #include <nuttx/mtd/mtd.h>
 #include <nuttx/mutex.h>
 
@@ -901,10 +902,12 @@ static int littlefs_ioctl(FAR struct file *filep, int 
cmd, unsigned long arg)
       case FIOC_FILEPATH:
         {
           FAR char *path = (FAR char *)(uintptr_t)arg;
+
           ret = inode_getpath(inode, path, PATH_MAX);
           if (ret >= 0)
             {
               size_t len = strlen(path);
+
               if (path[len - 1] != '/')
                 {
                   path[len++] = '/';
diff --git a/fs/mount/fs_automount.c b/fs/mount/fs_automount.c
index 2d5988aeea4..1afc7ac46ab 100644
--- a/fs/mount/fs_automount.c
+++ b/fs/mount/fs_automount.c
@@ -397,6 +397,7 @@ static int automount_ioctl(FAR struct file *filep, int cmd,
 static int automount_findinode(FAR const char *path)
 {
   struct inode_search_s desc;
+  FAR struct inode *inode;
   int ret;
 
   /* Make sure that we were given a path */
@@ -409,9 +410,14 @@ static int automount_findinode(FAR const char *path)
 
   /* Find the inode */
 
-  SETUP_SEARCH(&desc, path, false);
+  ret = inode_search_setup(&desc, path, false);
+  if (ret < 0)
+    {
+      inode_runlock();
+      return ret;
+    }
 
-  ret = inode_search(&desc);
+  ret = inode_search(&desc, &inode);
 
   /* Did we find it? */
 
@@ -424,7 +430,7 @@ static int automount_findinode(FAR const char *path)
 
   /* Yes.. is it a mount point? */
 
-  else if (INODE_IS_MOUNTPT(desc.node))
+  else if (INODE_IS_MOUNTPT(inode))
     {
       /* Yes.. we found a mountpoint at this path */
 
@@ -440,7 +446,7 @@ static int automount_findinode(FAR const char *path)
   /* Relinquish our exclusive access to the inode try and return the result */
 
   inode_runlock();
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
@@ -807,6 +813,7 @@ FAR void *automount_initialize(FAR const struct 
automount_lower_s *lower)
   int ret;
 #ifdef CONFIG_FS_AUTOMOUNTER_DRIVER
   FAR char *devpath = lib_get_pathbuffer();
+
   if (devpath == NULL)
     {
       return NULL;
@@ -917,6 +924,7 @@ void automount_uninitialize(FAR void *handle)
   if (priv->registered)
     {
       FAR char *devpath = lib_get_pathbuffer();
+
       if (devpath == NULL)
         {
           return;
diff --git a/fs/mount/fs_mount.c b/fs/mount/fs_mount.c
index 39c87e95cda..75eeb3c6874 100644
--- a/fs/mount/fs_mount.c
+++ b/fs/mount/fs_mount.c
@@ -372,24 +372,26 @@ int nx_mount(FAR const char *source, FAR const char 
*target,
     {
       ferr("ERROR: Failed to find block driver %s\n", source);
 
-      ret = -ENOTBLK;
-      goto errout;
+      return -ENOTBLK;
     }
 
   inode_lock();
 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
   /* Check if the inode already exists */
 
-  SETUP_SEARCH(&desc, target, false);
+  ret = inode_search_setup(&desc, target, false);
+  if (ret < 0)
+    {
+      goto errout_with_lock;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &mountpt_inode);
   if (ret >= 0)
     {
       /* Successfully found.  The reference count on the inode has been
        * incremented.
        */
 
-      mountpt_inode = desc.node;
       DEBUGASSERT(mountpt_inode != NULL);
 
       /* But is it a directory node (i.e., not a driver or other special
@@ -401,7 +403,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
           ferr("ERROR: target %s exists and is a special node\n", target);
           ret = -ENOTDIR;
           inode_release(mountpt_inode);
-          goto errout_with_lock;
+          goto errout_with_search;
         }
 
       /* Require search on ancestors and write on the mount target. */
@@ -410,7 +412,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
       if (ret < 0)
         {
           inode_release(mountpt_inode);
-          goto errout_with_lock;
+          goto errout_with_search;
         }
     }
 #endif
@@ -426,7 +428,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
 
       ferr("ERROR: Filesystem does not support bind\n");
       ret = -EINVAL;
-      goto errout_with_lock;
+      goto errout_with_search;
     }
 
   /* Increment reference count for the reference we pass to the file system */
@@ -468,7 +470,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
         }
 #endif
 
-      goto errout_with_lock;
+      goto errout_with_search;
     }
 
   /* Insert a dummy node -- we need to hold the inode semaphore
@@ -521,7 +523,7 @@ int nx_mount(FAR const char *source, FAR const char *target,
 #endif
 
 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #endif
 #ifdef CONFIG_FS_NOTIFY
   notify_create(target);
@@ -536,11 +538,13 @@ errout_with_bind:
       mops->unbind(fshandle, &drvr_inode, 0);
     }
 
-errout_with_lock:
-  inode_unlock();
+errout_with_search:
 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
+
+errout_with_lock:
 #endif
+  inode_unlock();
 
 errout_with_inode:
 #if defined(BDFS_SUPPORT) || defined(MDFS_SUPPORT)
@@ -550,7 +554,6 @@ errout_with_inode:
     }
 #endif
 
-errout:
   return ret;
 
 #else
diff --git a/fs/mount/fs_umount2.c b/fs/mount/fs_umount2.c
index a0cced51370..6ac21c7f405 100644
--- a/fs/mount/fs_umount2.c
+++ b/fs/mount/fs_umount2.c
@@ -72,9 +72,13 @@ int nx_umount2(FAR const char *target, unsigned int flags)
 
   /* Find the mountpt */
 
-  SETUP_SEARCH(&desc, target, false);
+  ret = inode_search_setup(&desc, target, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &mountpt_inode);
   if (ret < 0)
     {
       goto errout_with_search;
@@ -82,7 +86,6 @@ int nx_umount2(FAR const char *target, unsigned int flags)
 
   /* Get the search results */
 
-  mountpt_inode = desc.node;
   DEBUGASSERT(mountpt_inode != NULL);
 
   /* Verify that the inode is a mountpoint */
@@ -189,7 +192,7 @@ int nx_umount2(FAR const char *target, unsigned int flags)
       inode_release(blkdrvr_inode);
     }
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_unmount(target);
 #endif
@@ -208,7 +211,7 @@ errout_with_mountpt:
     }
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 
 errout:
   return ret;
diff --git a/fs/mqueue/mq_open.c b/fs/mqueue/mq_open.c
index 798ece2e264..cd6d05983a2 100644
--- a/fs/mqueue/mq_open.c
+++ b/fs/mqueue/mq_open.c
@@ -174,15 +174,13 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
 
   if (!mq || !mq_name || *mq_name == '\0')
     {
-      ret = -EINVAL;
-      goto errout;
+      return -EINVAL;
     }
 
   if (sizeof(CONFIG_FS_MQUEUE_VFS_PATH) + 1 + strlen(mq_name)
       >= MAX_MQUEUE_PATH)
     {
-      ret = -ENAMETOOLONG;
-      goto errout;
+      return -ENAMETOOLONG;
     }
 
   /* Were we asked to create it? */
@@ -199,8 +197,7 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
         {
           if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
             {
-              ret = -EINVAL;
-              goto errout;
+              return -EINVAL;
             }
         }
     }
@@ -235,15 +232,17 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
    * have incremented the reference count on the inode.
    */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      goto errout_with_lock;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret >= 0)
     {
       /* Something exists at this path.  Get the search results */
 
-      inode = desc.node;
-
       /* Verify that the inode is a message queue */
 
       if (!INODE_IS_MQUEUE(inode))
@@ -301,7 +300,7 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
           /* The mqueue does not exist and O_CREAT is not set */
 
           ret = -ENOENT;
-          goto errout_with_lock;
+          goto errout_with_search;
         }
 
       /* Create an inode in the pseudo-filesystem at this path */
@@ -312,7 +311,7 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
 
       if (ret < 0)
         {
-          goto errout_with_lock;
+          goto errout_with_search;
         }
 
       /* Allocate memory for the new message queue.  The new inode will
@@ -345,7 +344,7 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
         }
     }
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   leave_critical_section(flags);
 #ifdef CONFIG_FS_NOTIFY
   notify_open(fullpath, oflags);
@@ -355,11 +354,11 @@ static int file_mq_vopen(FAR struct file *mq, FAR const 
char *mq_name,
 errout_with_inode:
   inode_release(inode);
 
+errout_with_search:
+  inode_search_release(&desc);
+
 errout_with_lock:
-  RELEASE_SEARCH(&desc);
   leave_critical_section(flags);
-
-errout:
   return ret;
 }
 
diff --git a/fs/mqueue/mq_unlink.c b/fs/mqueue/mq_unlink.c
index 508231ee6f4..107683b1a59 100644
--- a/fs/mqueue/mq_unlink.c
+++ b/fs/mqueue/mq_unlink.c
@@ -113,9 +113,13 @@ int file_mq_unlink(FAR const char *mq_name)
 
   /* Get the inode for this message queue. */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* There is no inode that includes in this path */
@@ -125,8 +129,6 @@ int file_mq_unlink(FAR const char *mq_name)
 
   /* Get the search results */
 
-  inode = desc.node;
-
   /* Verify that what we found is, indeed, a message queue */
 
   if (!INODE_IS_MQUEUE(inode))
@@ -172,7 +174,7 @@ int file_mq_unlink(FAR const char *mq_name)
 
   inode_unlock();
   mq_inode_release(inode);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_unlink(fullpath);
 #endif
@@ -185,7 +187,7 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/partition/fs_partition.c b/fs/partition/fs_partition.c
index 9bb6fab7356..e751d00e336 100644
--- a/fs/partition/fs_partition.c
+++ b/fs/partition/fs_partition.c
@@ -29,6 +29,8 @@
 #include <assert.h>
 #include <stdio.h>
 
+#include <nuttx/lib/lib.h>
+
 #include "driver/driver.h"
 #include "partition.h"
 
diff --git a/fs/semaphore/sem_open.c b/fs/semaphore/sem_open.c
index 491e34945d2..f39f6f2e5e3 100644
--- a/fs/semaphore/sem_open.c
+++ b/fs/semaphore/sem_open.c
@@ -111,15 +111,17 @@ int nxsem_open(FAR sem_t **sem, FAR const char *name, int 
oflags, ...)
    * will have incremented the reference count on the inode.
    */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret >= 0)
     {
       /* Something exists at this path.  Get the search results */
 
-      inode = desc.node;
-
       /* Verify that the inode is a semaphore */
 
       if (!INODE_IS_NAMEDSEM(inode))
@@ -231,7 +233,7 @@ int nxsem_open(FAR sem_t **sem, FAR const char *name, int 
oflags, ...)
       *sem = &nsem->ns_sem;
     }
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_open(fullpath, oflags);
 #endif
@@ -241,7 +243,7 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/semaphore/sem_unlink.c b/fs/semaphore/sem_unlink.c
index 9fde96acc95..2aab6528777 100644
--- a/fs/semaphore/sem_unlink.c
+++ b/fs/semaphore/sem_unlink.c
@@ -78,9 +78,13 @@ int nxsem_unlink(FAR const char *name)
 
   /* Get the inode for this semaphore. */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* There is no inode that includes in this path */
@@ -90,8 +94,6 @@ int nxsem_unlink(FAR const char *name)
 
   /* Get the search results */
 
-  inode = desc.node;
-
   /* Verify that what we found is, indeed, a semaphore */
 
   if (!INODE_IS_NAMEDSEM(inode))
@@ -136,7 +138,7 @@ int nxsem_unlink(FAR const char *name)
 
   inode_unlock();
   ret = nxsem_close(&inode->u.i_nsem->ns_sem);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_unlink(fullpath);
 #endif
@@ -149,6 +151,6 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
diff --git a/fs/shm/shm_open.c b/fs/shm/shm_open.c
index e7db849cb90..c3360265951 100644
--- a/fs/shm/shm_open.c
+++ b/fs/shm/shm_open.c
@@ -82,23 +82,25 @@ static int file_shm_open(FAR struct file *shm, FAR const 
char *name,
 
   /* Get the inode for this shm object */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
   inode_lock();
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret >= 0)
     {
       /* Something exists at this path.  Get the search results */
 
-      inode = desc.node;
-
       /* Verify that the inode is an shm object */
 
       if (!INODE_IS_SHM(inode))
         {
           ret = -EINVAL;
           inode_release(inode);
-          goto errout_with_sem;
+          goto errout_with_lock;
         }
 
       /* It exists and is an shm object.  Check if the caller wanted to
@@ -109,7 +111,7 @@ static int file_shm_open(FAR struct file *shm, FAR const 
char *name,
         {
           ret = -EEXIST;
           inode_release(inode);
-          goto errout_with_sem;
+          goto errout_with_lock;
         }
 
 #ifdef CONFIG_FS_PERMISSION
@@ -117,7 +119,7 @@ static int file_shm_open(FAR struct file *shm, FAR const 
char *name,
       if (ret < 0)
         {
           inode_release(inode);
-          goto errout_with_sem;
+          goto errout_with_lock;
         }
 #endif
 
@@ -141,7 +143,7 @@ static int file_shm_open(FAR struct file *shm, FAR const 
char *name,
           /* The shm does not exist and O_CREAT is not set */
 
           ret = -ENOENT;
-          goto errout_with_sem;
+          goto errout_with_lock;
         }
 
       /* Create an inode in the pseudo-filesystem at this path */
@@ -149,7 +151,7 @@ static int file_shm_open(FAR struct file *shm, FAR const 
char *name,
       ret = inode_reserve(fullpath, mode, &inode);
       if (ret < 0)
         {
-          goto errout_with_sem;
+          goto errout_with_lock;
         }
 
       INODE_SET_SHM(inode);
@@ -163,9 +165,9 @@ static int file_shm_open(FAR struct file *shm, FAR const 
char *name,
   shm->f_oflags = oflags | O_NOFOLLOW;
   shm->f_inode = inode;
 
-errout_with_sem:
+errout_with_lock:
   inode_unlock();
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   if (ret >= 0)
     {
diff --git a/fs/shm/shm_unlink.c b/fs/shm/shm_unlink.c
index bd4850c8294..67960392f48 100644
--- a/fs/shm/shm_unlink.c
+++ b/fs/shm/shm_unlink.c
@@ -77,21 +77,23 @@ static int file_shm_unlink(FAR const char *name)
 
   /* Get the inode for this shm object */
 
-  SETUP_SEARCH(&desc, fullpath, false);
+  ret = inode_search_setup(&desc, fullpath, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
   inode_lock();
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* There is no inode that includes in this path */
 
-      goto errout_with_sem;
+      goto errout_with_lock;
     }
 
   /* Get the search results */
 
-  inode = desc.node;
-
   /* Verify that what we found is, indeed, an shm inode */
 
   if (!INODE_IS_SHM(inode))
@@ -134,9 +136,9 @@ static int file_shm_unlink(FAR const char *name)
 
 errout_with_inode:
   inode_release(inode);
-errout_with_sem:
+errout_with_lock:
   inode_unlock();
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   if (ret >= 0)
     {
diff --git a/fs/unionfs/fs_unionfs.c b/fs/unionfs/fs_unionfs.c
index 87da2bd577a..06b86cd32a5 100644
--- a/fs/unionfs/fs_unionfs.c
+++ b/fs/unionfs/fs_unionfs.c
@@ -2538,9 +2538,13 @@ static int unionfs_getmount(FAR const char *path, FAR 
struct inode **inode)
 
   /* Find the mountpt */
 
-  SETUP_SEARCH(&desc, path, false);
+  ret = inode_search_setup(&desc, path, false);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &minode);
   if (ret < 0)
     {
       /* Mountpoint inode not found */
@@ -2550,7 +2554,6 @@ static int unionfs_getmount(FAR const char *path, FAR 
struct inode **inode)
 
   /* Get the search results */
 
-  minode = desc.node;
   DEBUGASSERT(minode != NULL);
 
   /* Verify that the inode is a mountpoint.
@@ -2571,14 +2574,14 @@ static int unionfs_getmount(FAR const char *path, FAR 
struct inode **inode)
   /* Success! */
 
   *inode = minode;
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return OK;
 
 errout_with_inode:
   inode_release(minode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/vfs/fs_chstat.c b/fs/vfs/fs_chstat.c
index a8adcb342a3..6fdc6e31a48 100644
--- a/fs/vfs/fs_chstat.c
+++ b/fs/vfs/fs_chstat.c
@@ -54,9 +54,13 @@ static int chstat_recursive(FAR const char *path,
 
   /* Get an inode for this path */
 
-  SETUP_SEARCH(&desc, path, true);
+  ret = inode_search_setup(&desc, path, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* This name does not refer to an inode in the pseudo file system and
@@ -68,7 +72,6 @@ static int chstat_recursive(FAR const char *path,
 
   /* Get the search results */
 
-  inode = desc.node;
   DEBUGASSERT(inode != NULL);
 
   ret = inode_checkpathperm(inode, 0, 0);
@@ -113,7 +116,7 @@ static int chstat_recursive(FAR const char *path,
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/vfs/fs_close.c b/fs/vfs/fs_close.c
index aa8ddbf5b33..4f87712cab4 100644
--- a/fs/vfs/fs_close.c
+++ b/fs/vfs/fs_close.c
@@ -34,6 +34,7 @@
 
 #include <nuttx/cancelpt.h>
 #include <nuttx/fs/fs.h>
+#include <nuttx/lib/lib.h>
 
 #ifdef CONFIG_FDSAN
 #  include <android/fdsan.h>
diff --git a/fs/vfs/fs_link.c b/fs/vfs/fs_link.c
index 2b8c652a67a..e31b73d2232 100644
--- a/fs/vfs/fs_link.c
+++ b/fs/vfs/fs_link.c
@@ -80,36 +80,37 @@ int link(FAR const char *path1, FAR const char *path2)
   struct inode_search_s desc_path2;
   FAR struct inode *target = NULL;
   FAR struct inode *newinode = NULL;
-  int errcode;
   int ret;
 
   if (path1 == NULL || path2 == NULL)
     {
-      errcode = EINVAL;
+      ret = -EINVAL;
       goto errout;
     }
 
   if (*path1 == '\0' || *path2 == '\0')
     {
-      errcode = ENOENT;
+      ret = -ENOENT;
       goto errout;
     }
 
-  SETUP_SEARCH(&desc_path1, path1, false);
-  ret = inode_find(&desc_path1);
+  ret = inode_search_setup(&desc_path1, path1, false);
   if (ret < 0)
     {
-      errcode = -ret;
-      goto errout_with_search_path1;
+      goto errout;
     }
 
-  target = desc_path1.node;
+  ret = inode_find(&desc_path1, &target);
+  if (ret < 0)
+    {
+      goto errout_with_search_path1;
+    }
 
   if (INODE_GET_NLINK(target) >= _POSIX_LINK_MAX)
     {
       /* Too many links to the target inode */
 
-      errcode = EMLINK;
+      ret = -EMLINK;
       goto errout_with_target;
     }
 
@@ -117,13 +118,15 @@ int link(FAR const char *path1, FAR const char *path2)
    * 'path2' does not lie on a mounted volume.
    */
 
-  SETUP_SEARCH(&desc_path2, path2, true);
+  ret = inode_search_setup(&desc_path2, path2, true);
+  if (ret < 0)
+    {
+      goto errout_with_target;
+    }
 
-  ret = inode_find(&desc_path2);
+  ret = inode_find(&desc_path2, &newinode);
   if (ret >= 0)
     {
-      newinode = desc_path2.node;
-
       /* Something exists at the path2 where we are trying to create the
        * link.
        */
@@ -138,7 +141,7 @@ int link(FAR const char *path1, FAR const char *path2)
 
           if (newinode != target)
             {
-              errcode = EXDEV;
+              ret = -EXDEV;
               goto errout_with_newinode;
             }
 
@@ -152,7 +155,6 @@ int link(FAR const char *path1, FAR const char *path2)
                                            desc_path2.relpath);
               if (ret < 0)
                 {
-                  errcode = -ret;
                   goto errout_with_newinode;
                 }
             }
@@ -160,7 +162,7 @@ int link(FAR const char *path1, FAR const char *path2)
             {
               /* Hard links within this type of fs are not supported */
 
-              errcode = ENOSYS;
+              ret = -ENOSYS;
               goto errout_with_newinode;
             }
         }
@@ -169,7 +171,7 @@ int link(FAR const char *path1, FAR const char *path2)
         {
           /* A node already exists in the pseudofs at 'path2' */
 
-          errcode = EEXIST;
+          ret = -EEXIST;
           goto errout_with_newinode;
         }
     }
@@ -187,7 +189,6 @@ int link(FAR const char *path1, FAR const char *path2)
 
       if (ret != -ENOENT && ret != -ENOTDIR)
         {
-          errcode = -ret;
           goto errout_with_newinode;
         }
 
@@ -195,7 +196,7 @@ int link(FAR const char *path1, FAR const char *path2)
 
       if (INODE_IS_MOUNTPT(target))
         {
-          errcode = EXDEV;
+          ret = -EXDEV;
           goto errout_with_newinode;
         }
 
@@ -216,15 +217,14 @@ int link(FAR const char *path1, FAR const char *path2)
       inode_unlock();
       if (ret < 0)
         {
-          errcode = -ret;
           goto errout_with_newinode;
         }
     }
 
   /* Hard link successfully created */
 
-  RELEASE_SEARCH(&desc_path1);
-  RELEASE_SEARCH(&desc_path2);
+  inode_search_release(&desc_path1);
+  inode_search_release(&desc_path2);
   inode_release(target);
 
 #ifdef CONFIG_FS_NOTIFY
@@ -234,14 +234,14 @@ int link(FAR const char *path1, FAR const char *path2)
 
 errout_with_newinode:
   inode_release(newinode);
-  RELEASE_SEARCH(&desc_path2);
+  inode_search_release(&desc_path2);
 errout_with_target:
   inode_release(target);
 errout_with_search_path1:
-  RELEASE_SEARCH(&desc_path1);
+  inode_search_release(&desc_path1);
 
 errout:
-  set_errno(errcode);
+  set_errno(-ret);
   return ERROR;
 }
 
diff --git a/fs/vfs/fs_mkdir.c b/fs/vfs/fs_mkdir.c
index 6efc790ed11..8f0d6613f46 100644
--- a/fs/vfs/fs_mkdir.c
+++ b/fs/vfs/fs_mkdir.c
@@ -64,28 +64,30 @@ int mkdir(const char *pathname, mode_t mode)
 {
   struct inode_search_s desc;
   FAR struct inode *inode;
-  int errcode;
   int ret;
 
   mode &= ~getumask();
 
   /* Find the inode that includes this path */
 
-  SETUP_SEARCH(&desc, pathname, false);
+  ret = inode_search_setup(&desc, pathname, false);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret >= 0)
     {
       /* An inode was found that includes this path and possibly refers to a
        * mountpoint.
        */
 
-      inode = desc.node;
       DEBUGASSERT(inode != NULL);
 
       if (desc.relpath[0] == '\0')
         {
-          errcode = EEXIST;
+          ret = -EEXIST;
           goto errout_with_inode;
         }
 
@@ -96,14 +98,13 @@ int mkdir(const char *pathname, mode_t mode)
         {
           /* The inode is not a mountpoint */
 
-          errcode = ENXIO;
+          ret = -ENXIO;
           goto errout_with_inode;
         }
 
       ret = inode_checkpathperm(inode, 0, 0);
       if (ret < 0)
         {
-          errcode = -ret;
           goto errout_with_inode;
         }
 
@@ -116,13 +117,12 @@ int mkdir(const char *pathname, mode_t mode)
           ret = inode->u.i_mops->mkdir(inode, desc.relpath, mode);
           if (ret < 0)
             {
-              errcode = -ret;
               goto errout_with_inode;
             }
         }
       else
         {
-          errcode = ENOSYS;
+          ret = -ENOSYS;
           goto errout_with_inode;
         }
 
@@ -132,7 +132,7 @@ int mkdir(const char *pathname, mode_t mode)
 #else
       /* But mountpoints are not supported in this configuration */
 
-      errcode = EEXIST;
+      ret = -EEXIST;
       goto errout_with_inode;
 #endif
     }
@@ -159,21 +159,20 @@ int mkdir(const char *pathname, mode_t mode)
 
       if (ret < 0)
         {
-          errcode = -ret;
           goto errout_with_search;
         }
     }
 #else
   else
     {
-      errcode = ENXIO;
+      ret = -ENXIO;
       goto errout_with_search;
     }
 #endif
 
   /* Directory successfully created */
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_mkdir(pathname);
 #endif
@@ -183,8 +182,10 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
-  set_errno(errcode);
+  inode_search_release(&desc);
+
+errout:
+  set_errno(-ret);
   return ERROR;
 }
 
diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c
index 35518d77fbf..d4b13b8d4de 100644
--- a/fs/vfs/fs_open.c
+++ b/fs/vfs/fs_open.c
@@ -100,15 +100,19 @@ static int file_vopen(FAR struct file *filep, FAR const 
char *path,
 
   /* Get an inode for this file */
 
-  SETUP_SEARCH(&desc, path, (oflags & O_NOFOLLOW) != 0);
+  ret = inode_search_setup(&desc, path, (oflags & O_NOFOLLOW) != 0);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
 #ifdef CONFIG_PSEUDOFS_FILE
       if ((oflags & O_CREAT) != 0)
         {
-          ret = pseudofile_create(&desc.node, path, mode);
+          ret = pseudofile_create(&inode, path, mode);
         }
 #endif
 
@@ -125,7 +129,6 @@ static int file_vopen(FAR struct file *filep, FAR const 
char *path,
 
   /* Get the search results */
 
-  inode = desc.node;
   DEBUGASSERT(inode != NULL);
 
 #ifdef CONFIG_FS_LINKS
@@ -161,7 +164,7 @@ static int file_vopen(FAR struct file *filep, FAR const 
char *path,
       /* Release the inode reference */
 
       inode_release(inode);
-      RELEASE_SEARCH(&desc);
+      inode_search_release(&desc);
 
       /* Get the file structure of the opened character driver proxy */
 
@@ -264,7 +267,7 @@ static int file_vopen(FAR struct file *filep, FAR const 
char *path,
       goto errout_with_inode;
     }
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_open(path, filep->f_oflags);
 #endif
@@ -275,7 +278,7 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/vfs/fs_readlink.c b/fs/vfs/fs_readlink.c
index ad301ec46b3..51f09ad18cc 100644
--- a/fs/vfs/fs_readlink.c
+++ b/fs/vfs/fs_readlink.c
@@ -71,7 +71,6 @@ ssize_t readlink(FAR const char *path, FAR char *buf, size_t 
bufsize)
 {
   struct inode_search_s desc;
   FAR struct inode *node;
-  int errcode;
   int ret;
 
   DEBUGASSERT(path != NULL && buf != NULL && bufsize > 0);
@@ -80,18 +79,18 @@ ssize_t readlink(FAR const char *path, FAR char *buf, 
size_t bufsize)
    * symbolic link node.
    */
 
-  SETUP_SEARCH(&desc, path, true);
+  ret = inode_search_setup(&desc, path, true);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &node);
   if (ret < 0)
     {
-      errcode = -ret;
       goto errout_with_search;
     }
 
-  /* Get the search results */
-
-  node = desc.node;
   DEBUGASSERT(node != NULL);
 
 #ifndef CONFIG_DISABLE_MOUNTPOINT
@@ -106,13 +105,12 @@ ssize_t readlink(FAR const char *path, FAR char *buf, 
size_t bufsize)
           ret = node->u.i_mops->readlink(node, desc.relpath, buf, bufsize);
           if (ret < 0)
             {
-              errcode = -ret;
               goto errout_with_inode;
             }
         }
       else
         {
-          errcode = ENOSYS;
+          ret = -ENOSYS;
           goto errout_with_inode;
         }
     }
@@ -122,7 +120,6 @@ ssize_t readlink(FAR const char *path, FAR char *buf, 
size_t bufsize)
       ret = inode_checkpathperm(node, 0, 0);
       if (ret < 0)
         {
-          errcode = -ret;
           goto errout_with_inode;
         }
 
@@ -134,7 +131,7 @@ ssize_t readlink(FAR const char *path, FAR char *buf, 
size_t bufsize)
 
       if (!INODE_IS_SOFTLINK(node))
         {
-          errcode = EINVAL;
+          ret = -EINVAL;
           goto errout_with_inode;
         }
 
@@ -146,15 +143,17 @@ ssize_t readlink(FAR const char *path, FAR char *buf, 
size_t bufsize)
   /* Release our reference on the inode and return the length */
 
   inode_release(node);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return strlen(buf);
 
 errout_with_inode:
   inode_release(node);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
-  set_errno(errcode);
+  inode_search_release(&desc);
+
+errout:
+  set_errno(-ret);
   return ERROR;
 }
 
diff --git a/fs/vfs/fs_rename.c b/fs/vfs/fs_rename.c
index 571320420c0..7bfb580c2c2 100644
--- a/fs/vfs/fs_rename.c
+++ b/fs/vfs/fs_rename.c
@@ -71,7 +71,6 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
                         FAR const char *newpath)
 {
   struct inode_search_s newdesc;
-  struct inode_search_s olddesc;
   FAR struct inode *newinode;
   FAR char *subdir = NULL;
 #ifdef CONFIG_FS_NOTIFY
@@ -86,7 +85,11 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
 
   inode_lock();
 
-  SETUP_SEARCH(&newdesc, newpath, true);
+  ret = inode_search_setup(&newdesc, newpath, true);
+  if (ret < 0)
+    {
+      goto errout_with_lock;
+    }
 
   /* Ancestor X_OK was already checked by rename() via
    * inode_checkpathperm(oldinode, ...).  Still require parent W_OK here
@@ -96,19 +99,18 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
   ret = inode_checkperm(oldparent, W_OK);
   if (ret < 0)
     {
-      goto errout_with_lock;
+      goto errout_with_newsearch;
     }
 
   /* According to POSIX, any new inode at this path should be removed
    * first, provided that it is not a directory.
    */
 
-  ret = inode_search(&newdesc);
+  ret = inode_search(&newdesc, &newinode);
   if (ret >= 0)
     {
       /* We found it.  Get the search results */
 
-      newinode = newdesc.node;
       DEBUGASSERT(newinode != NULL);
 
       /* If the old and new inodes are the same, then this is an attempt to
@@ -118,7 +120,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
       if (oldinode == newinode)
         {
           ret = OK;
-          goto errout_with_lock;
+          goto errout_with_newsearch;
         }
 
 #ifndef CONFIG_DISABLE_MOUNTPOINT
@@ -127,7 +129,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
       if (INODE_IS_MOUNTPT(newinode))
         {
           ret = -EXDEV;
-          goto errout_with_lock;
+          goto errout_with_newsearch;
         }
 #endif
 
@@ -154,7 +156,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
             {
               subdir = NULL;
               ret = -ENOMEM;
-              goto errout_with_lock;
+              goto errout_with_newsearch;
             }
 
           newpath = subdir;
@@ -174,7 +176,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
           ret = inode_remove(newpath);
           if (ret < 0 && ret != -EBUSY)
             {
-              goto errout_with_lock;
+              goto errout_with_newsearch;
             }
 
 #ifdef CONFIG_FS_NOTIFY
@@ -191,19 +193,7 @@ static int pseudorename(FAR const char *oldpath, FAR 
struct inode *oldinode,
   ret = inode_reserve(newpath, 0777, &newinode);
   if (ret < 0)
     {
-      goto errout_with_lock;
-    }
-
-  /* Re-resolve the source under the same lock before unlinking it. */
-
-  SETUP_SEARCH(&olddesc, oldpath, true);
-  ret = inode_search(&olddesc);
-  RELEASE_SEARCH(&olddesc);
-  if (ret < 0 || olddesc.node != oldinode)
-    {
-      inode_remove(newpath);
-      ret = -ENOENT;
-      goto errout_with_lock;
+      goto errout_with_newsearch;
     }
 
   /* Copy the inode state from the old inode to the newly allocated inode */
@@ -248,7 +238,7 @@ static int pseudorename(FAR const char *oldpath, FAR struct 
inode *oldinode,
       /* Remove the new node we just recreated */
 
       inode_remove(newpath);
-      goto errout_with_lock;
+      goto errout_with_newsearch;
     }
 
   /* Remove all of the children from the unlinked inode */
@@ -257,8 +247,10 @@ static int pseudorename(FAR const char *oldpath, FAR 
struct inode *oldinode,
   oldinode->i_parent = NULL;
   ret = OK;
 
+errout_with_newsearch:
+  inode_search_release(&newdesc);
+
 errout_with_lock:
-  RELEASE_SEARCH(&newdesc);
   inode_unlock();
 
 #ifdef CONFIG_FS_NOTIFY
@@ -315,8 +307,13 @@ static int mountptrename(FAR const char *oldpath, FAR 
struct inode *oldinode,
    * mountpoint
    */
 
-  SETUP_SEARCH(&newdesc, newpath, true);
-  ret = inode_find(&newdesc);
+  ret = inode_search_setup(&newdesc, newpath, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = inode_find(&newdesc, &newinode);
   if (ret < 0)
     {
       /* There is no mountpoint that includes in this path */
@@ -326,7 +323,6 @@ static int mountptrename(FAR const char *oldpath, FAR 
struct inode *oldinode,
 
   /* Get the search results */
 
-  newinode   = newdesc.node;
   newrelpath = newdesc.relpath;
   DEBUGASSERT(newinode != NULL && newrelpath != NULL);
 
@@ -512,7 +508,7 @@ errout_with_newinode:
   inode_release(newinode);
 
 errout_with_newsearch:
-  RELEASE_SEARCH(&newdesc);
+  inode_search_release(&newdesc);
   if (subdir != NULL)
     {
       fs_heap_free(subdir);
@@ -553,8 +549,13 @@ int rename(FAR const char *oldpath, FAR const char 
*newpath)
 
   /* Get an inode that includes the oldpath */
 
-  SETUP_SEARCH(&olddesc, oldpath, true);
-  ret = inode_find(&olddesc);
+  ret = inode_search_setup(&olddesc, oldpath, true);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  ret = inode_find(&olddesc, &oldinode);
   if (ret < 0)
     {
       /* There is no inode that includes in this path */
@@ -562,9 +563,6 @@ int rename(FAR const char *oldpath, FAR const char *newpath)
       goto errout_with_oldsearch;
     }
 
-  /* Get the search results */
-
-  oldinode = olddesc.node;
   DEBUGASSERT(oldinode != NULL);
 
   ret = inode_checkpathperm(oldinode, 0, 0);
@@ -594,7 +592,7 @@ int rename(FAR const char *oldpath, FAR const char *newpath)
   inode_release(oldinode);
 
 errout_with_oldsearch:
-  RELEASE_SEARCH(&olddesc);
+  inode_search_release(&olddesc);
 
 errout:
   if (ret < 0)
diff --git a/fs/vfs/fs_rmdir.c b/fs/vfs/fs_rmdir.c
index f2911085d53..bcf4dab1a9f 100644
--- a/fs/vfs/fs_rmdir.c
+++ b/fs/vfs/fs_rmdir.c
@@ -62,7 +62,6 @@ int rmdir(FAR const char *pathname)
 {
   struct inode_search_s desc;
   FAR struct inode *inode;
-  int errcode;
   int ret;
 
   /* Get an inode for the directory (or for the mountpoint containing the
@@ -70,20 +69,20 @@ int rmdir(FAR const char *pathname)
    * on the inode if one is found.
    */
 
-  SETUP_SEARCH(&desc, pathname, true);
+  ret = inode_search_setup(&desc, pathname, true);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* There is no inode that includes in this path */
 
-      errcode = -ret;
       goto errout_with_search;
     }
 
-  /* Get the search results */
-
-  inode = desc.node;
   DEBUGASSERT(inode != NULL);
 
 #ifndef CONFIG_DISABLE_MOUNTPOINT
@@ -94,7 +93,6 @@ int rmdir(FAR const char *pathname)
       ret = inode_checkpathperm(inode, 0, 0);
       if (ret < 0)
         {
-          errcode = -ret;
           goto errout_with_inode;
         }
 
@@ -107,13 +105,12 @@ int rmdir(FAR const char *pathname)
           ret = inode->u.i_mops->rmdir(inode, desc.relpath);
           if (ret < 0)
             {
-              errcode = -ret;
               goto errout_with_inode;
             }
         }
       else
         {
-          errcode = ENOSYS;
+          ret = -ENOSYS;
           goto errout_with_inode;
         }
     }
@@ -133,7 +130,7 @@ int rmdir(FAR const char *pathname)
 
       if (inode->i_child)
         {
-          errcode = ENOTEMPTY;
+          ret = -ENOTEMPTY;
           goto errout_with_inode;
         }
 
@@ -149,26 +146,25 @@ int rmdir(FAR const char *pathname)
 
       if (ret < 0 && ret != -EBUSY)
         {
-          errcode = -ret;
           goto errout_with_inode;
         }
     }
   else
     {
-      errcode = ENOTDIR;
+      ret = -ENOTDIR;
       goto errout_with_inode;
     }
 #else
-    {
-      errcode = ENXIO;
-      goto errout_with_inode;
-    }
+  {
+    ret = -ENXIO;
+    goto errout_with_inode;
+  }
 #endif
 
   /* Successfully removed the directory */
 
   inode_release(inode);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_unlink(pathname);
 #endif
@@ -177,8 +173,9 @@ int rmdir(FAR const char *pathname)
 errout_with_inode:
   inode_release(inode);
 errout_with_search:
-  RELEASE_SEARCH(&desc);
-  set_errno(errcode);
+  inode_search_release(&desc);
+errout:
+  set_errno(-ret);
   return ERROR;
 }
 
diff --git a/fs/vfs/fs_stat.c b/fs/vfs/fs_stat.c
index 9eefb401e5e..f5b7586a341 100644
--- a/fs/vfs/fs_stat.c
+++ b/fs/vfs/fs_stat.c
@@ -88,9 +88,13 @@ static int stat_recursive(FAR const char *path,
 
   /* Get an inode for this path */
 
-  SETUP_SEARCH(&desc, path, true);
+  ret = inode_search_setup(&desc, path, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* This name does not refer to an inode in the pseudo file system and
@@ -102,7 +106,6 @@ static int stat_recursive(FAR const char *path,
 
   /* Get the search results */
 
-  inode = desc.node;
   DEBUGASSERT(inode != NULL);
 
   ret = inode_checkpathperm(inode, 0, 0);
@@ -153,7 +156,7 @@ static int stat_recursive(FAR const char *path,
 
   inode_release(inode);
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 
diff --git a/fs/vfs/fs_statfs.c b/fs/vfs/fs_statfs.c
index 70d796c3b5f..212ee783a9a 100644
--- a/fs/vfs/fs_statfs.c
+++ b/fs/vfs/fs_statfs.c
@@ -93,9 +93,13 @@ int statfs(FAR const char *path, FAR struct statfs *buf)
 
   /* Get an inode for this file */
 
-  SETUP_SEARCH(&desc, path, false);
+  ret = inode_search_setup(&desc, path, false);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* This name does not refer to a psudeo-inode and there is no
@@ -107,7 +111,6 @@ int statfs(FAR const char *path, FAR struct statfs *buf)
 
   /* Get the search results */
 
-  inode = desc.node;
   DEBUGASSERT(inode != NULL);
 
   ret = inode_checkpathperm(inode, 0, 0);
@@ -154,7 +157,7 @@ int statfs(FAR const char *path, FAR struct statfs *buf)
   /* Successfully statfs'ed the file */
 
   inode_release(inode);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return OK;
 
   /* Failure conditions always set the errno appropriately */
@@ -163,7 +166,7 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 
 errout:
   set_errno(-ret);
diff --git a/fs/vfs/fs_symlink.c b/fs/vfs/fs_symlink.c
index 76cac2bad73..5ced61110e0 100644
--- a/fs/vfs/fs_symlink.c
+++ b/fs/vfs/fs_symlink.c
@@ -81,12 +81,11 @@ int symlink(FAR const char *path1, FAR const char *path2)
 {
   struct inode_search_s desc;
   FAR struct inode *inode = NULL;
-  int errcode;
   int ret;
 
   if (path1 == NULL)
     {
-      errcode = EINVAL;
+      ret = -EINVAL;
       goto errout;
     }
 
@@ -94,9 +93,13 @@ int symlink(FAR const char *path1, FAR const char *path2)
    * 'path2' does not lie on a mounted volume.
    */
 
-  SETUP_SEARCH(&desc, path2, false);
+  ret = inode_search_setup(&desc, path2, false);
+  if (ret < 0)
+    {
+      goto errout;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret >= 0)
     {
       /* Something exists at the path2 where we are trying to create the
@@ -106,16 +109,15 @@ int symlink(FAR const char *path1, FAR const char *path2)
 #ifndef CONFIG_DISABLE_MOUNTPOINT
       /* Check if the inode is a mountpoint. */
 
-      DEBUGASSERT(desc.node != NULL);
-      if (INODE_IS_MOUNTPT(desc.node))
+      DEBUGASSERT(inode != NULL);
+      if (INODE_IS_MOUNTPT(inode))
         {
-          if (desc.node->u.i_mops && desc.node->u.i_mops->symlink)
+          if (inode->u.i_mops && inode->u.i_mops->symlink)
             {
-              ret = desc.node->u.i_mops->symlink(desc.node, path1,
-                                                 desc.relpath);
+              ret = inode->u.i_mops->symlink(inode, path1,
+                                             desc.relpath);
               if (ret < 0)
                 {
-                  errcode = -ret;
                   goto errout_with_inode;
                 }
             }
@@ -123,7 +125,7 @@ int symlink(FAR const char *path1, FAR const char *path2)
             {
               /* Symbolic links within this type of fs are not supported */
 
-              errcode = ENOSYS;
+              ret = -ENOSYS;
               goto errout_with_inode;
             }
         }
@@ -132,7 +134,7 @@ int symlink(FAR const char *path1, FAR const char *path2)
         {
           /* A node already exists in the pseudofs at 'path1' */
 
-          errcode = EEXIST;
+          ret = -EEXIST;
           goto errout_with_inode;
         }
     }
@@ -149,7 +151,7 @@ int symlink(FAR const char *path1, FAR const char *path2)
 
       if (newpath2 == NULL)
         {
-          errcode = ENOMEM;
+          ret = -ENOMEM;
           goto errout_with_search;
         }
 
@@ -173,14 +175,13 @@ int symlink(FAR const char *path1, FAR const char *path2)
       if (ret < 0)
         {
           fs_heap_free(newpath2);
-          errcode = -ret;
           goto errout_with_search;
         }
     }
 
   /* Symbolic link successfully created */
 
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_create(path2);
 #endif
@@ -190,10 +191,10 @@ errout_with_inode:
   inode_release(inode);
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 
 errout:
-  set_errno(errcode);
+  set_errno(-ret);
   return ERROR;
 }
 
diff --git a/fs/vfs/fs_unlink.c b/fs/vfs/fs_unlink.c
index 9d7be5dc545..eb890f43a2c 100644
--- a/fs/vfs/fs_unlink.c
+++ b/fs/vfs/fs_unlink.c
@@ -68,9 +68,13 @@ int nx_unlink(FAR const char *pathname)
    * which may be a symbolic link)
    */
 
-  SETUP_SEARCH(&desc, pathname, true);
+  ret = inode_search_setup(&desc, pathname, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
 
-  ret = inode_find(&desc);
+  ret = inode_find(&desc, &inode);
   if (ret < 0)
     {
       /* There is no inode that includes in this path */
@@ -78,9 +82,6 @@ int nx_unlink(FAR const char *pathname)
       goto errout_with_search;
     }
 
-  /* Get the search results */
-
-  inode = desc.node;
   DEBUGASSERT(inode != NULL);
 
 #ifndef CONFIG_DISABLE_MOUNTPOINT
@@ -193,7 +194,7 @@ int nx_unlink(FAR const char *pathname)
   /* Successfully unlinked */
 
   inode_release(inode);
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
 #ifdef CONFIG_FS_NOTIFY
   notify_unlink(pathname);
 #endif
@@ -205,7 +206,7 @@ errout_with_inode:
 #endif
 
 errout_with_search:
-  RELEASE_SEARCH(&desc);
+  inode_search_release(&desc);
   return ret;
 }
 

Reply via email to