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

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

commit 86193c95caee67692f62f87e06d0ebc96add7b65
Author: zhengyu16 <[email protected]>
AuthorDate: Tue Nov 25 22:19:48 2025 +0800

    fs/hostfs: add link, symlink, readlink and lstat support
    
    Implemented link(), symlink(), readlink() and lstat() in hostfs.
    
    Signed-off-by: zhengyu16 <[email protected]>
---
 arch/arm/src/common/arm_hostfs.c       |  28 +++
 arch/arm64/src/common/arm64_hostfs.c   |  22 ++
 arch/risc-v/src/common/riscv_hostfs.c  |  22 ++
 arch/sim/src/nuttx-names.in            |   3 +
 arch/sim/src/sim/posix/sim_hostfs.c    |  71 +++++++
 arch/sim/src/sim/win/sim_hostfs.c      |  39 ++++
 arch/xtensa/src/common/xtensa_hostfs.c |  22 ++
 fs/hostfs/hostfs.c                     | 372 ++++++++++++++++++++++++++++++---
 include/nuttx/fs/hostfs.h              |  13 ++
 9 files changed, 568 insertions(+), 24 deletions(-)

diff --git a/arch/arm/src/common/arm_hostfs.c b/arch/arm/src/common/arm_hostfs.c
index 8c47a46138c..682861cf442 100644
--- a/arch/arm/src/common/arm_hostfs.c
+++ b/arch/arm/src/common/arm_hostfs.c
@@ -370,3 +370,31 @@ int host_chstat(const char *path, const struct stat *buf, 
int flags)
 {
   return -ENOSYS;
 }
+
+#ifdef CONFIG_FS_LINKS
+int host_link(const char *path1, const char *path2)
+{
+  /* ARM semihosting doesn't support hard links */
+
+  return -ENOSYS;
+}
+
+int host_symlink(const char *target, const char *linkpath)
+{
+  /* ARM semihosting doesn't support symbolic links */
+
+  return -ENOSYS;
+}
+
+ssize_t host_readlink(const char *path, char *buf, size_t bufsize)
+{
+  /* ARM semihosting doesn't support symbolic links */
+
+  return -ENOSYS;
+}
+
+int host_lstat(const char *path, struct stat *buf)
+{
+  return -ENOSYS;
+}
+#endif /* CONFIG_FS_LINKS */
diff --git a/arch/arm64/src/common/arm64_hostfs.c 
b/arch/arm64/src/common/arm64_hostfs.c
index ff4419292c5..452268b10a6 100644
--- a/arch/arm64/src/common/arm64_hostfs.c
+++ b/arch/arm64/src/common/arm64_hostfs.c
@@ -370,3 +370,25 @@ int host_chstat(const char *path, const struct stat *buf, 
int flags)
 {
   return -ENOSYS;
 }
+
+#ifdef CONFIG_FS_LINKS
+int host_link(const char *path1, const char *path2)
+{
+  return -ENOSYS;
+}
+
+int host_symlink(const char *target, const char *linkpath)
+{
+  return -ENOSYS;
+}
+
+ssize_t host_readlink(const char *path, char *buf, size_t bufsize)
+{
+  return -ENOSYS;
+}
+
+int host_lstat(const char *path, struct stat *buf)
+{
+  return -ENOSYS;
+}
+#endif /* CONFIG_FS_LINKS */
diff --git a/arch/risc-v/src/common/riscv_hostfs.c 
b/arch/risc-v/src/common/riscv_hostfs.c
index 8a87c74afdf..cd319f941a2 100644
--- a/arch/risc-v/src/common/riscv_hostfs.c
+++ b/arch/risc-v/src/common/riscv_hostfs.c
@@ -368,3 +368,25 @@ int host_chstat(const char *path, const struct stat *buf, 
int flags)
 {
   return -ENOSYS;
 }
+
+#ifdef CONFIG_FS_LINKS
+int host_link(const char *path1, const char *path2)
+{
+  return -ENOSYS;
+}
+
+int host_symlink(const char *target, const char *linkpath)
+{
+  return -ENOSYS;
+}
+
+ssize_t host_readlink(const char *path, char *buf, size_t bufsize)
+{
+  return -ENOSYS;
+}
+
+int host_lstat(const char *path, struct stat *buf)
+{
+  return -ENOSYS;
+}
+#endif /* CONFIG_FS_LINKS */
diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in
index 9a47af018a8..3c7f1caa744 100644
--- a/arch/sim/src/nuttx-names.in
+++ b/arch/sim/src/nuttx-names.in
@@ -75,9 +75,11 @@ NXSYMBOLS(getpid)
 NXSYMBOLS(getsockopt)
 NXSYMBOLS(if_nametoindex)
 NXSYMBOLS(ioctl)
+NXSYMBOLS(link)
 NXSYMBOLS(listen)
 NXSYMBOLS(longjmp)
 NXSYMBOLS(lseek)
+NXSYMBOLS(lstat)
 NXSYMBOLS(malloc)
 NXSYMBOLS(malloc_size)
 NXSYMBOLS(malloc_usable_size)
@@ -154,6 +156,7 @@ NXSYMBOLS(strchr)
 NXSYMBOLS(strerror)
 NXSYMBOLS(strlen)
 NXSYMBOLS(strtol)
+NXSYMBOLS(symlink)
 NXSYMBOLS(sysconf)
 NXSYMBOLS(syslog)
 NXSYMBOLS(system)
diff --git a/arch/sim/src/sim/posix/sim_hostfs.c 
b/arch/sim/src/sim/posix/sim_hostfs.c
index 67380d14038..d95f07ee992 100644
--- a/arch/sim/src/sim/posix/sim_hostfs.c
+++ b/arch/sim/src/sim/posix/sim_hostfs.c
@@ -820,3 +820,74 @@ int host_chstat(const char *path, const struct 
nuttx_stat_s *buf, int flags)
 
   return 0;
 }
+
+/****************************************************************************
+ * Name: host_link
+ ****************************************************************************/
+
+#ifdef CONFIG_FS_LINKS
+int host_link(const char *path1, const char *path2)
+{
+  int ret = link(path1, path2);
+  if (ret < 0)
+    {
+      ret = -errno;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: host_symlink
+ ****************************************************************************/
+
+int host_symlink(const char *target, const char *linkpath)
+{
+  int ret = symlink(target, linkpath);
+  if (ret < 0)
+    {
+      ret = -errno;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: host_readlink
+ ****************************************************************************/
+
+nuttx_ssize_t host_readlink(const char *path, char *buf,
+                            nuttx_size_t bufsize)
+{
+  ssize_t ret = readlink(path, buf, bufsize);
+  if (ret < 0)
+    {
+      ret = -errno;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: host_lstat
+ ****************************************************************************/
+
+int host_lstat(const char *path, struct nuttx_stat_s *buf)
+{
+  struct stat hostbuf;
+  int ret;
+
+  /* Call the host's lstat routine */
+
+  ret = lstat(path, &hostbuf);
+  if (ret < 0)
+    {
+      ret = -errno;
+    }
+
+  /* Map the return values */
+
+  host_stat_convert(&hostbuf, buf);
+  return ret;
+}
+#endif /* CONFIG_FS_LINKS */
diff --git a/arch/sim/src/sim/win/sim_hostfs.c 
b/arch/sim/src/sim/win/sim_hostfs.c
index 65f3208f085..e20a5ff5b42 100644
--- a/arch/sim/src/sim/win/sim_hostfs.c
+++ b/arch/sim/src/sim/win/sim_hostfs.c
@@ -461,3 +461,42 @@ int host_chstat(const char *path, const struct 
nuttx_stat_s *buf, int flags)
 {
   return -ENOSYS;
 }
+
+/****************************************************************************
+ * Name: host_link
+ ****************************************************************************/
+
+#ifdef CONFIG_FS_LINKS
+int host_link(const char *path1, const char *path2)
+{
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: host_symlink
+ ****************************************************************************/
+
+int host_symlink(const char *target, const char *linkpath)
+{
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: host_readlink
+ ****************************************************************************/
+
+nuttx_ssize_t host_readlink(const char *path, char *buf,
+                            nuttx_size_t bufsize)
+{
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: host_lstat
+ ****************************************************************************/
+
+int host_lstat(const char *path, struct nuttx_stat_s *buf)
+{
+  return -ENOSYS;
+}
+#endif /* CONFIG_FS_LINKS */
diff --git a/arch/xtensa/src/common/xtensa_hostfs.c 
b/arch/xtensa/src/common/xtensa_hostfs.c
index d803bce9083..075b342bae1 100644
--- a/arch/xtensa/src/common/xtensa_hostfs.c
+++ b/arch/xtensa/src/common/xtensa_hostfs.c
@@ -256,3 +256,25 @@ int host_chstat(const char *path, const struct stat *buf, 
int flags)
 {
   return -ENOSYS;
 }
+
+#ifdef CONFIG_FS_LINKS
+int host_link(const char *path1, const char *path2)
+{
+  return -ENOSYS;
+}
+
+int host_symlink(const char *target, const char *linkpath)
+{
+  return -ENOSYS;
+}
+
+ssize_t host_readlink(const char *path, char *buf, size_t bufsize)
+{
+  return -ENOSYS;
+}
+
+int host_lstat(const char *path, struct stat *buf)
+{
+  return -ENOSYS;
+}
+#endif /* CONFIG_FS_LINKS */
diff --git a/fs/hostfs/hostfs.c b/fs/hostfs/hostfs.c
index c9f24b5fd4a..8d6f80f02b1 100644
--- a/fs/hostfs/hostfs.c
+++ b/fs/hostfs/hostfs.c
@@ -117,6 +117,21 @@ static int     hostfs_chstat(FAR struct inode *mountpt,
                              FAR const char *relpath,
                              FAR const struct stat *buf, int flags);
 
+#ifdef CONFIG_FS_LINKS
+static int     hostfs_link(FAR struct inode *mountpt,
+                           FAR const char *relpath1,
+                           FAR const char *relpath2);
+static int     hostfs_symlink(FAR struct inode *mountpt,
+                              FAR const char *path1,
+                              FAR const char *relpath2);
+static ssize_t hostfs_readlink(FAR struct inode *mountpt,
+                               FAR const char *relpath,
+                               FAR char *buf, size_t bufsize);
+static int     hostfs_lstat(FAR struct inode *mountpt,
+                            FAR const char *relpath,
+                            FAR struct stat *buf);
+#endif
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -160,6 +175,15 @@ const struct mountpt_operations g_hostfs_operations =
   hostfs_rename,        /* rename */
   hostfs_stat,          /* stat */
   hostfs_chstat,        /* chstat */
+  NULL,                 /* syncfs */
+  NULL,                 /* ioctldir */
+  NULL,                 /* permission */
+#ifdef CONFIG_FS_LINKS
+  hostfs_link,          /* link */
+  hostfs_symlink,       /* symlink */
+  hostfs_readlink,      /* readlink */
+  hostfs_lstat,         /* lstat */
+#endif
 };
 
 /****************************************************************************
@@ -237,7 +261,7 @@ static int hostfs_open(FAR struct file *filep, FAR const 
char *relpath,
   FAR struct inode *inode;
   FAR struct hostfs_mountpt_s *fs;
   FAR struct hostfs_ofile_s  *hf;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   size_t len;
   int ret;
 
@@ -254,12 +278,18 @@ static int hostfs_open(FAR struct file *filep, FAR const 
char *relpath,
 
   DEBUGASSERT(fs != NULL);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Take the lock */
 
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_path;
     }
 
   /* Allocate memory for the open file */
@@ -274,7 +304,7 @@ static int hostfs_open(FAR struct file *filep, FAR const 
char *relpath,
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Try to open the file in the host file system */
 
@@ -328,6 +358,10 @@ errout_with_buffer:
 
 errout_with_lock:
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
+
   if (ret == -EINVAL)
     {
       ret = -EIO;
@@ -839,20 +873,27 @@ static int hostfs_opendir(FAR struct inode *mountpt, FAR 
const char *relpath,
 {
   FAR struct hostfs_mountpt_s *fs;
   FAR struct hostfs_dir_s *hdir;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Recover our private data from the inode instance */
 
   fs = mountpt->i_private;
   hdir = fs_heap_zalloc(sizeof(struct hostfs_dir_s));
   if (hdir == NULL)
     {
-      return -ENOMEM;
+      ret = -ENOMEM;
+      goto errout_with_path;
     }
 
   /* Take the lock */
@@ -865,7 +906,7 @@ static int hostfs_opendir(FAR struct inode *mountpt, FAR 
const char *relpath,
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Call the host's opendir function */
 
@@ -878,6 +919,7 @@ static int hostfs_opendir(FAR struct inode *mountpt, FAR 
const char *relpath,
 
   *dir = (FAR struct fs_dirent_s *)hdir;
   nxmutex_unlock(&fs->fs_lock);
+  lib_put_tempbuffer(path);
   return OK;
 
 errout_with_lock:
@@ -885,6 +927,9 @@ errout_with_lock:
 
 errout_with_hdir:
   fs_heap_free(hdir);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
   return ret;
 }
 
@@ -1204,13 +1249,19 @@ static int hostfs_statfs(FAR struct inode *mountpt, FAR 
struct statfs *buf)
 static int hostfs_unlink(FAR struct inode *mountpt, FAR const char *relpath)
 {
   FAR struct hostfs_mountpt_s *fs;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt && mountpt->i_private);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Get the mountpoint private data from the inode structure */
 
   fs = mountpt->i_private;
@@ -1218,18 +1269,21 @@ static int hostfs_unlink(FAR struct inode *mountpt, FAR 
const char *relpath)
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_path;
     }
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Call the host fs to perform the unlink */
 
   ret = host_unlink(path);
 
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
   return ret;
 }
 
@@ -1244,13 +1298,19 @@ static int hostfs_mkdir(FAR struct inode *mountpt, FAR 
const char *relpath,
                         mode_t mode)
 {
   FAR struct hostfs_mountpt_s *fs;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt && mountpt->i_private);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Get the mountpoint private data from the inode structure */
 
   fs = mountpt->i_private;
@@ -1258,18 +1318,21 @@ static int hostfs_mkdir(FAR struct inode *mountpt, FAR 
const char *relpath,
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_path;
     }
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Call the host FS to do the mkdir */
 
   ret = host_mkdir(path, mode);
 
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
   return ret;
 }
 
@@ -1283,13 +1346,19 @@ static int hostfs_mkdir(FAR struct inode *mountpt, FAR 
const char *relpath,
 int hostfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
 {
   FAR struct hostfs_mountpt_s *fs;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt && mountpt->i_private);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Get the mountpoint private data from the inode structure */
 
   fs = mountpt->i_private;
@@ -1299,18 +1368,21 @@ int hostfs_rmdir(FAR struct inode *mountpt, FAR const 
char *relpath)
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_path;
     }
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Call the host FS to do the mkdir */
 
   ret = host_rmdir(path);
 
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
   return ret;
 }
 
@@ -1325,14 +1397,27 @@ int hostfs_rename(FAR struct inode *mountpt, FAR const 
char *oldrelpath,
                   FAR const char *newrelpath)
 {
   FAR struct hostfs_mountpt_s *fs;
-  char oldpath[HOSTFS_MAX_PATH];
-  char newpath[HOSTFS_MAX_PATH];
+  FAR char *oldpath;
+  FAR char *newpath;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt && mountpt->i_private);
 
+  oldpath = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (oldpath == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  newpath = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (newpath == NULL)
+    {
+      ret = -ENOMEM;
+      goto errout_with_oldpath;
+    }
+
   /* Get the mountpoint private data from the inode structure */
 
   fs = mountpt->i_private;
@@ -1340,7 +1425,7 @@ int hostfs_rename(FAR struct inode *mountpt, FAR const 
char *oldrelpath,
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_newpath;
     }
 
   /* Append to the host's root directory */
@@ -1355,6 +1440,12 @@ int hostfs_rename(FAR struct inode *mountpt, FAR const 
char *oldrelpath,
   ret = host_rename(oldpath, newpath);
 
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_newpath:
+  lib_put_tempbuffer(newpath);
+
+errout_with_oldpath:
+  lib_put_tempbuffer(oldpath);
   return ret;
 }
 
@@ -1369,13 +1460,19 @@ static int hostfs_stat(FAR struct inode *mountpt, FAR 
const char *relpath,
                        FAR struct stat *buf)
 {
   FAR struct hostfs_mountpt_s *fs;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt && mountpt->i_private);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Get the mountpoint private data from the inode structure */
 
   fs = mountpt->i_private;
@@ -1383,18 +1480,21 @@ static int hostfs_stat(FAR struct inode *mountpt, FAR 
const char *relpath,
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_path;
     }
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Call the host FS to do the stat operation */
 
   ret = host_stat(path, buf);
 
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
   return ret;
 }
 
@@ -1409,13 +1509,19 @@ static int hostfs_chstat(FAR struct inode *mountpt, FAR 
const char *relpath,
                          FAR const struct stat *buf, int flags)
 {
   FAR struct hostfs_mountpt_s *fs;
-  char path[HOSTFS_MAX_PATH];
+  FAR char *path;
   int ret;
 
   /* Sanity checks */
 
   DEBUGASSERT(mountpt && mountpt->i_private);
 
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
   /* Get the mountpoint private data from the inode structure */
 
   fs = mountpt->i_private;
@@ -1423,20 +1529,238 @@ static int hostfs_chstat(FAR struct inode *mountpt, 
FAR const char *relpath,
   ret = nxmutex_lock(&fs->fs_lock);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_path;
     }
 
   /* Append to the host's root directory */
 
-  hostfs_mkpath(fs, relpath, path, sizeof(path));
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
 
   /* Call the host FS to do the chstat operation */
 
   ret = host_chstat(path, buf, flags);
 
   nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
+  return ret;
+}
+
+#ifdef CONFIG_FS_LINKS
+/****************************************************************************
+ * Name: hostfs_link
+ *
+ * Description: Create a hard link
+ *
+ ****************************************************************************/
+
+static int hostfs_link(FAR struct inode *mountpt, FAR const char *relpath1,
+                       FAR const char *relpath2)
+{
+  FAR struct hostfs_mountpt_s *fs;
+  FAR char *path1;
+  FAR char *path2;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  path1 = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path1 == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  path2 = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path2 == NULL)
+    {
+      ret = -ENOMEM;
+      goto errout_with_path1;
+    }
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path2;
+    }
+
+  /* Append to the host's root directory */
+
+  hostfs_mkpath(fs, relpath1, path1, HOSTFS_MAX_PATH);
+  hostfs_mkpath(fs, relpath2, path2, HOSTFS_MAX_PATH);
+
+  /* Call the host FS to create the hard link */
+
+  ret = host_link(path1, path2);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path2:
+  lib_put_tempbuffer(path2);
+
+errout_with_path1:
+  lib_put_tempbuffer(path1);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: hostfs_symlink
+ *
+ * Description: Create a symbolic link
+ *
+ ****************************************************************************/
+
+static int hostfs_symlink(FAR struct inode *mountpt,
+                          FAR const char *path1,
+                          FAR const char *relpath2)
+{
+  FAR struct hostfs_mountpt_s *fs;
+  FAR char *fullpath2;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  fullpath2 = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (fullpath2 == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path;
+    }
+
+  /* Build the full path for the link location (relpath2)
+   * The target (path1) is used as-is, allowing relative or absolute paths
+   */
+
+  hostfs_mkpath(fs, relpath2, fullpath2, HOSTFS_MAX_PATH);
+
+  /* Call the host FS to create the symbolic link */
+
+  ret = host_symlink(path1, fullpath2);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(fullpath2);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: hostfs_readlink
+ *
+ * Description: Read the target of a symbolic link
+ *
+ ****************************************************************************/
+
+static ssize_t hostfs_readlink(FAR struct inode *mountpt,
+                               FAR const char *relpath,
+                               FAR char *buf, size_t bufsize)
+{
+  FAR struct hostfs_mountpt_s *fs;
+  FAR char *path;
+  ssize_t ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path;
+    }
+
+  /* Append to the host's root directory */
+
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
+
+  /* Call the host FS to read the symbolic link */
+
+  ret = host_readlink(path, buf, bufsize);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: hostfs_lstat
+ *
+ * Description: Return information about a file or directory (don't follow
+ *              symbolic links)
+ *
+ ****************************************************************************/
+
+static int hostfs_lstat(FAR struct inode *mountpt, FAR const char *relpath,
+                        FAR struct stat *buf)
+{
+  FAR struct hostfs_mountpt_s *fs;
+  FAR char *path;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  path = lib_get_tempbuffer(HOSTFS_MAX_PATH);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path;
+    }
+
+  /* Append to the host's root directory */
+
+  hostfs_mkpath(fs, relpath, path, HOSTFS_MAX_PATH);
+
+  /* Call the host FS to do the lstat operation */
+
+  ret = host_lstat(path, buf);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
   return ret;
 }
+#endif /* CONFIG_FS_LINKS */
 
 /****************************************************************************
  * Public Functions
diff --git a/include/nuttx/fs/hostfs.h b/include/nuttx/fs/hostfs.h
index 601b210db5a..e3e4aa6933c 100644
--- a/include/nuttx/fs/hostfs.h
+++ b/include/nuttx/fs/hostfs.h
@@ -256,6 +256,13 @@ int           host_rename(const char *oldpath, const char 
*newpath);
 int           host_stat(const char *path, struct nuttx_stat_s *buf);
 int           host_chstat(const char *path,
                           const struct nuttx_stat_s *buf, int flags);
+#ifdef CONFIG_FS_LINKS
+int           host_link(const char *path1, const char *path2);
+int           host_symlink(const char *target, const char *linkpath);
+nuttx_ssize_t host_readlink(const char *path, char *buf,
+                            nuttx_size_t bufsize);
+int           host_lstat(const char *path, struct nuttx_stat_s *buf);
+#endif
 #else
 int           host_open(const char *pathname, int flags, int mode);
 int           host_close(int fd);
@@ -280,6 +287,12 @@ int           host_rename(const char *oldpath, const char 
*newpath);
 int           host_stat(const char *path, struct stat *buf);
 int           host_chstat(const char *path,
                           const struct stat *buf, int flags);
+#ifdef CONFIG_FS_LINKS
+int           host_link(const char *path1, const char *path2);
+int           host_symlink(const char *target, const char *linkpath);
+ssize_t       host_readlink(const char *path, char *buf, size_t bufsize);
+int           host_lstat(const char *path, struct stat *buf);
+#endif
 #endif /* __SIM__ */
 
 #endif /* __INCLUDE_NUTTX_FS_HOSTFS_H */

Reply via email to