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 41ec966941f38d0ce5bf1aa46e73cb9167cfa1a7
Author: zhengyu16 <[email protected]>
AuthorDate: Tue Dec 2 14:13:28 2025 +0800

    fs/rpmsgfs: add link, symlink, readlink and lstat support
    
    Implement link(), symlink(), readlink() and lstat() in rpmsgfs.
    
    Signed-off-by: zhengyu16 <[email protected]>
---
 fs/rpmsgfs/rpmsgfs.c        | 239 ++++++++++++++++++++++++++++++++++++++++++++
 fs/rpmsgfs/rpmsgfs.h        |  18 ++++
 fs/rpmsgfs/rpmsgfs_client.c | 138 +++++++++++++++++++++++++
 fs/rpmsgfs/rpmsgfs_server.c | 176 +++++++++++++++++++++++---------
 4 files changed, 522 insertions(+), 49 deletions(-)

diff --git a/fs/rpmsgfs/rpmsgfs.c b/fs/rpmsgfs/rpmsgfs.c
index b19d0aaa52a..28c55c6923e 100644
--- a/fs/rpmsgfs/rpmsgfs.c
+++ b/fs/rpmsgfs/rpmsgfs.c
@@ -147,6 +147,21 @@ static int     rpmsgfs_chstat(FAR struct inode *mountpt,
                               FAR const char *relpath,
                               FAR const struct stat *buf, int flags);
 
+#ifdef CONFIG_FS_LINKS
+static int     rpmsgfs_link(FAR struct inode *mountpt,
+                            FAR const char *relpath1,
+                            FAR const char *relpath2);
+static int     rpmsgfs_symlink(FAR struct inode *mountpt,
+                               FAR const char *target,
+                               FAR const char *relpath);
+static ssize_t rpmsgfs_readlink(FAR struct inode *mountpt,
+                                FAR const char *relpath,
+                                FAR char *buf, size_t bufsize);
+static int     rpmsgfs_lstat(FAR struct inode *mountpt,
+                             FAR const char *relpath,
+                             FAR struct stat *buf);
+#endif
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -190,6 +205,16 @@ const struct mountpt_operations g_rpmsgfs_operations =
   rpmsgfs_rename,        /* rename */
   rpmsgfs_stat,          /* stat */
   rpmsgfs_chstat,        /* chstat */
+  NULL,                  /* syncfs */
+  NULL,                  /* ioctldir */
+  NULL,                  /* permission */
+
+#ifdef CONFIG_FS_LINKS
+  rpmsgfs_link,          /* link */
+  rpmsgfs_symlink,       /* symlink */
+  rpmsgfs_readlink,      /* readlink */
+  rpmsgfs_lstat,         /* lstat */
+#endif
 };
 
 /****************************************************************************
@@ -1551,3 +1576,217 @@ static int rpmsgfs_chstat(FAR struct inode *mountpt, 
FAR const char *relpath,
   lib_put_pathbuffer(path);
   return ret;
 }
+
+#ifdef CONFIG_FS_LINKS
+/****************************************************************************
+ * Name: rpmsgfs_link
+ *
+ * Description: Create a hard link
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_link(FAR struct inode *mountpt, FAR const char *relpath1,
+                        FAR const char *relpath2)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR char *path1;
+  FAR char *path2;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  path1 = lib_get_tempbuffer(PATH_MAX);
+  if (path1 == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  path2 = lib_get_tempbuffer(PATH_MAX);
+  if (path2 == NULL)
+    {
+      ret = -ENOMEM;
+      goto errout_with_path1;
+    }
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path2;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath1, path1, PATH_MAX);
+  rpmsgfs_mkpath(fs, relpath2, path2, PATH_MAX);
+
+  /* Call the host FS to do the link operation */
+
+  ret = rpmsgfs_client_link(fs->handle, path1, path2);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path2:
+  lib_put_tempbuffer(path2);
+errout_with_path1:
+  lib_put_tempbuffer(path1);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_symlink
+ *
+ * Description: Create a symbolic link
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_symlink(FAR struct inode *mountpt, FAR const char *target,
+                           FAR const char *relpath)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR char *linkpath;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  linkpath = lib_get_tempbuffer(PATH_MAX);
+  if (linkpath == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path;
+    }
+
+  /* Append to the host's root directory.
+   * Note: target is stored as-is (it's a path in the remote system),
+   * only linkpath needs to be converted to host path.
+   */
+
+  rpmsgfs_mkpath(fs, relpath, linkpath, PATH_MAX);
+
+  /* Call the host FS to do the symlink operation */
+
+  ret = rpmsgfs_client_symlink(fs->handle, target, linkpath);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(linkpath);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_readlink
+ *
+ * Description: Read the target of a symbolic link
+ *
+ ****************************************************************************/
+
+static ssize_t rpmsgfs_readlink(FAR struct inode *mountpt,
+                                FAR const char *relpath, FAR char *buf,
+                                size_t bufsize)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR char *path;
+  ssize_t ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  path = lib_get_tempbuffer(PATH_MAX);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, PATH_MAX);
+
+  /* Call the host FS to do the readlink operation */
+
+  ret = rpmsgfs_client_readlink(fs->handle, path, buf, bufsize);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rpmsgfs_lstat
+ *
+ * Description: Return information about a file or directory (without
+ *              following symlinks)
+ *
+ ****************************************************************************/
+
+static int rpmsgfs_lstat(FAR struct inode *mountpt, FAR const char *relpath,
+                         FAR struct stat *buf)
+{
+  FAR struct rpmsgfs_mountpt_s *fs;
+  FAR char *path;
+  int ret;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(mountpt && mountpt->i_private);
+
+  /* Get the mountpoint private data from the inode structure */
+
+  fs = mountpt->i_private;
+
+  path = lib_get_tempbuffer(PATH_MAX);
+  if (path == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  ret = nxmutex_lock(&fs->fs_lock);
+  if (ret < 0)
+    {
+      goto errout_with_path;
+    }
+
+  /* Append to the host's root directory */
+
+  rpmsgfs_mkpath(fs, relpath, path, PATH_MAX);
+
+  /* Call the host FS to do the lstat operation */
+
+  ret = rpmsgfs_client_lstat(fs->handle, path, buf);
+
+  nxmutex_unlock(&fs->fs_lock);
+
+errout_with_path:
+  lib_put_tempbuffer(path);
+  return ret;
+}
+#endif
diff --git a/fs/rpmsgfs/rpmsgfs.h b/fs/rpmsgfs/rpmsgfs.h
index aa6aa805d95..da44f8ee90d 100644
--- a/fs/rpmsgfs/rpmsgfs.h
+++ b/fs/rpmsgfs/rpmsgfs.h
@@ -61,6 +61,10 @@
 #define RPMSGFS_STAT            20
 #define RPMSGFS_FCHSTAT         21
 #define RPMSGFS_CHSTAT          22
+#define RPMSGFS_SYMLINK         23
+#define RPMSGFS_READLINK        24
+#define RPMSGFS_LINK            25
+#define RPMSGFS_LSTAT           26
 
 /****************************************************************************
  * Public Types
@@ -202,6 +206,10 @@ begin_packed_struct struct rpmsgfs_mkdir_s
 #define rpmsgfs_rmdir_s rpmsgfs_opendir_s
 #define rpmsgfs_rename_s rpmsgfs_opendir_s
 #define rpmsgfs_stat_s rpmsgfs_fstat_s
+#define rpmsgfs_lstat_s rpmsgfs_fstat_s
+#define rpmsgfs_symlink_s rpmsgfs_opendir_s
+#define rpmsgfs_readlink_s rpmsgfs_opendir_s
+#define rpmsgfs_link_s rpmsgfs_opendir_s
 
 begin_packed_struct struct rpmsgfs_fchstat_s
 {
@@ -258,6 +266,16 @@ int       rpmsgfs_client_stat(FAR void *handle, FAR const 
char *path,
                               FAR struct stat *buf);
 int       rpmsgfs_client_chstat(FAR void *handle, FAR const char *path,
                                 FAR const struct stat *buf, int flags);
+#ifdef CONFIG_FS_LINKS
+int       rpmsgfs_client_symlink(FAR void *handle, FAR const char *target,
+                                 FAR const char *linkpath);
+ssize_t   rpmsgfs_client_readlink(FAR void *handle, FAR const char *pathname,
+                                  FAR char *buf, size_t bufsize);
+int       rpmsgfs_client_link(FAR void *handle, FAR const char *path1,
+                              FAR const char *path2);
+int       rpmsgfs_client_lstat(FAR void *handle, FAR const char *path,
+                               FAR struct stat *buf);
+#endif
 
 /****************************************************************************
  * Public Function Prototypes
diff --git a/fs/rpmsgfs/rpmsgfs_client.c b/fs/rpmsgfs/rpmsgfs_client.c
index dd1883a2ce2..5eb5c396a48 100644
--- a/fs/rpmsgfs/rpmsgfs_client.c
+++ b/fs/rpmsgfs/rpmsgfs_client.c
@@ -83,6 +83,11 @@ static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint 
*ept,
 static int rpmsgfs_init_handler(FAR struct rpmsg_endpoint *ept,
                                    FAR void *data, size_t len,
                                    uint32_t src, FAR void *priv);
+#ifdef CONFIG_FS_LINKS
+static int rpmsgfs_readlink_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv);
+#endif
 static void rpmsgfs_device_created(struct rpmsg_device *rdev,
                                    FAR void *priv_);
 static void rpmsgfs_device_destroy(struct rpmsg_device *rdev,
@@ -124,6 +129,12 @@ static const rpmsg_ept_cb g_rpmsgfs_handler[] =
   [RPMSGFS_STAT]      = rpmsgfs_stat_handler,
   [RPMSGFS_FCHSTAT]   = rpmsgfs_default_handler,
   [RPMSGFS_CHSTAT]    = rpmsgfs_default_handler,
+#ifdef CONFIG_FS_LINKS
+  [RPMSGFS_SYMLINK]   = rpmsgfs_default_handler,
+  [RPMSGFS_READLINK]  = rpmsgfs_readlink_handler,
+  [RPMSGFS_LINK]      = rpmsgfs_default_handler,
+  [RPMSGFS_LSTAT]     = rpmsgfs_stat_handler,
+#endif
 };
 
 /****************************************************************************
@@ -289,6 +300,27 @@ static int rpmsgfs_init_handler(FAR struct rpmsg_endpoint 
*ept,
   rpmsg_post(&ept_priv->ept, &ept_priv->wait);
   return 0;
 }
+#ifdef CONFIG_FS_LINKS
+static int rpmsgfs_readlink_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_header_s *header = data;
+  FAR struct rpmsgfs_cookie_s *cookie =
+      (struct rpmsgfs_cookie_s *)(uintptr_t)header->cookie;
+  FAR struct rpmsgfs_readlink_s *rsp = data;
+
+  cookie->result = header->result;
+  if (cookie->result > 0)
+    {
+      memcpy(cookie->data, rsp->pathname, cookie->result);
+    }
+
+  rpmsg_post(ept, &cookie->sem);
+
+  return 0;
+}
+#endif
 
 static FAR void *rpmsgfs_get_tx_payload_buffer(FAR struct rpmsgfs_s *priv,
                                                FAR uint32_t *len)
@@ -1029,3 +1061,109 @@ int rpmsgfs_client_chstat(FAR void *handle, FAR const 
char *path,
   return rpmsgfs_send_recv(priv, RPMSGFS_CHSTAT, false,
           (struct rpmsgfs_header_s *)msg, len, NULL);
 }
+
+int rpmsgfs_client_symlink(FAR void *handle, FAR const char *target,
+                           FAR const char *linkpath)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_symlink_s *msg;
+  size_t len1;
+  size_t len2;
+  size_t len;
+  uint32_t space;
+
+  len1 = strlen(target) + 1;
+  len2 = strlen(linkpath) + 1;
+  len = sizeof(*msg) + len1 + len2;
+
+  msg = rpmsgfs_get_tx_payload_buffer(priv, &space);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  memcpy(msg->pathname, target, len1);
+  memcpy(msg->pathname + len1, linkpath, len2);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_SYMLINK, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+ssize_t rpmsgfs_client_readlink(FAR void *handle, FAR const char *pathname,
+                                FAR char *buf, size_t bufsize)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_readlink_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len = sizeof(*msg) + strlen(pathname) + 1;
+
+  msg = rpmsgfs_get_tx_payload_buffer(priv, &space);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  strlcpy(msg->pathname, pathname, space - sizeof(*msg));
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_READLINK, false,
+          (struct rpmsgfs_header_s *)msg, len, buf);
+}
+
+int rpmsgfs_client_link(FAR void *handle, FAR const char *path1,
+                        FAR const char *path2)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_link_s *msg;
+  size_t len1;
+  size_t len2;
+  size_t len;
+  uint32_t space;
+
+  len1 = strlen(path1) + 1;
+  len2 = strlen(path2) + 1;
+  len = sizeof(*msg) + len1 + len2;
+
+  msg = rpmsgfs_get_tx_payload_buffer(priv, &space);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  memcpy(msg->pathname, path1, len1);
+  memcpy(msg->pathname + len1, path2, len2);
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_LINK, false,
+          (struct rpmsgfs_header_s *)msg, len, NULL);
+}
+
+int rpmsgfs_client_lstat(FAR void *handle, FAR const char *path,
+                         FAR struct stat *buf)
+{
+  FAR struct rpmsgfs_s *priv = handle;
+  FAR struct rpmsgfs_lstat_s *msg;
+  uint32_t space;
+  size_t len;
+
+  len = sizeof(*msg) + strlen(path) + 1;
+
+  msg = rpmsgfs_get_tx_payload_buffer(priv, &space);
+  if (!msg)
+    {
+      return -ENOMEM;
+    }
+
+  DEBUGASSERT(len <= space);
+
+  strlcpy(msg->pathname, path, space - sizeof(*msg));
+
+  return rpmsgfs_send_recv(priv, RPMSGFS_LSTAT, false,
+          (struct rpmsgfs_header_s *)msg, len, buf);
+}
diff --git a/fs/rpmsgfs/rpmsgfs_server.c b/fs/rpmsgfs/rpmsgfs_server.c
index 4377bf14f99..5dfd5d2a78f 100644
--- a/fs/rpmsgfs/rpmsgfs_server.c
+++ b/fs/rpmsgfs/rpmsgfs_server.c
@@ -126,7 +126,20 @@ static int rpmsgfs_fchstat_handler(FAR struct 
rpmsg_endpoint *ept,
 static int rpmsgfs_chstat_handler(FAR struct rpmsg_endpoint *ept,
                                   FAR void *data, size_t len,
                                   uint32_t src, FAR void *priv);
-
+#ifdef CONFIG_FS_LINKS
+static int rpmsgfs_symlink_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv);
+static int rpmsgfs_readlink_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv);
+static int rpmsgfs_link_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv);
+static int rpmsgfs_lstat_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv);
+#endif
 static bool rpmsgfs_ns_match(FAR struct rpmsg_device *rdev,
                              FAR void *priv_, FAR const char *name,
                              uint32_t dest);
@@ -165,6 +178,12 @@ static const rpmsg_ept_cb g_rpmsgfs_handler[] =
   [RPMSGFS_STAT]      = rpmsgfs_stat_handler,
   [RPMSGFS_FCHSTAT]   = rpmsgfs_fchstat_handler,
   [RPMSGFS_CHSTAT]    = rpmsgfs_chstat_handler,
+#ifdef CONFIG_FS_LINKS
+  [RPMSGFS_SYMLINK]   = rpmsgfs_symlink_handler,
+  [RPMSGFS_READLINK]  = rpmsgfs_readlink_handler,
+  [RPMSGFS_LINK]      = rpmsgfs_link_handler,
+  [RPMSGFS_LSTAT]     = rpmsgfs_lstat_handler,
+#endif
 };
 
 /****************************************************************************
@@ -313,6 +332,48 @@ static FAR void *rpmsgfs_get_dir(
   return dir;
 }
 
+static void rpmsgfs_get_statbuf(FAR struct stat *st,
+                                FAR struct rpmsgfs_stat_priv_s *rst)
+{
+  st->st_dev           = rst->dev;
+  st->st_ino           = rst->ino;
+  st->st_mode          = rst->mode;
+  st->st_nlink         = rst->nlink;
+  st->st_uid           = rst->uid;
+  st->st_gid           = rst->gid;
+  st->st_rdev          = rst->rdev;
+  st->st_size          = rst->size;
+  st->st_atim.tv_sec   = rst->atim_sec;
+  st->st_atim.tv_nsec  = rst->atim_nsec;
+  st->st_mtim.tv_sec   = rst->mtim_sec;
+  st->st_mtim.tv_nsec  = rst->mtim_nsec;
+  st->st_ctim.tv_sec   = rst->ctim_sec;
+  st->st_ctim.tv_nsec  = rst->ctim_nsec;
+  st->st_blksize       = rst->blksize;
+  st->st_blocks        = rst->blocks;
+}
+
+static void rpmsgfs_set_statbuf(FAR struct rpmsgfs_stat_priv_s *rst,
+                                FAR const struct stat *st)
+{
+  rst->dev        = st->st_dev;
+  rst->ino        = st->st_ino;
+  rst->mode       = st->st_mode;
+  rst->nlink      = st->st_nlink;
+  rst->uid        = st->st_uid;
+  rst->gid        = st->st_gid;
+  rst->rdev       = st->st_rdev;
+  rst->size       = st->st_size;
+  rst->atim_sec   = st->st_atim.tv_sec;
+  rst->atim_nsec  = st->st_atim.tv_nsec;
+  rst->mtim_sec   = st->st_mtim.tv_sec;
+  rst->mtim_nsec  = st->st_mtim.tv_nsec;
+  rst->ctim_sec   = st->st_ctim.tv_sec;
+  rst->ctim_nsec  = st->st_ctim.tv_nsec;
+  rst->blksize    = st->st_blksize;
+  rst->blocks     = st->st_blocks;
+}
+
 static int rpmsgfs_open_handler(FAR struct rpmsg_endpoint *ept,
                                 FAR void *data, size_t len,
                                 uint32_t src, FAR void *priv)
@@ -538,22 +599,7 @@ static int rpmsgfs_fstat_handler(FAR struct rpmsg_endpoint 
*ept,
       ret = file_fstat(filep, &buf);
       if (ret >= 0)
         {
-          msg->buf.dev       = buf.st_dev;
-          msg->buf.ino       = buf.st_ino;
-          msg->buf.mode      = buf.st_mode;
-          msg->buf.nlink     = buf.st_nlink;
-          msg->buf.uid       = buf.st_uid;
-          msg->buf.gid       = buf.st_gid;
-          msg->buf.rdev      = buf.st_rdev;
-          msg->buf.size      = buf.st_size;
-          msg->buf.atim_sec  = buf.st_atim.tv_sec;
-          msg->buf.atim_nsec = buf.st_atim.tv_nsec;
-          msg->buf.mtim_sec  = buf.st_mtim.tv_sec;
-          msg->buf.mtim_nsec = buf.st_mtim.tv_nsec;
-          msg->buf.ctim_sec  = buf.st_ctim.tv_sec;
-          msg->buf.ctim_nsec = buf.st_ctim.tv_nsec;
-          msg->buf.blksize   = buf.st_blksize;
-          msg->buf.blocks    = buf.st_blocks;
+          rpmsgfs_set_statbuf(&msg->buf, &buf);
         }
     }
 
@@ -760,22 +806,7 @@ static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint 
*ept,
   ret = nx_stat(msg->pathname, &buf, 1);
   if (ret >= 0)
     {
-      msg->buf.dev       = buf.st_dev;
-      msg->buf.ino       = buf.st_ino;
-      msg->buf.mode      = buf.st_mode;
-      msg->buf.nlink     = buf.st_nlink;
-      msg->buf.uid       = buf.st_uid;
-      msg->buf.gid       = buf.st_gid;
-      msg->buf.rdev      = buf.st_rdev;
-      msg->buf.size      = buf.st_size;
-      msg->buf.atim_sec  = buf.st_atim.tv_sec;
-      msg->buf.atim_nsec = buf.st_atim.tv_nsec;
-      msg->buf.mtim_sec  = buf.st_mtim.tv_sec;
-      msg->buf.mtim_nsec = buf.st_mtim.tv_nsec;
-      msg->buf.ctim_sec  = buf.st_ctim.tv_sec;
-      msg->buf.ctim_nsec = buf.st_ctim.tv_nsec;
-      msg->buf.blksize   = buf.st_blksize;
-      msg->buf.blocks    = buf.st_blocks;
+      rpmsgfs_set_statbuf(&msg->buf, &buf);
     }
 
   msg->header.result = ret;
@@ -794,22 +825,7 @@ static int rpmsgfs_fchstat_handler(FAR struct 
rpmsg_endpoint *ept,
   filep = rpmsgfs_get_file(priv, msg->fd);
   if (filep != NULL)
     {
-      buf.st_dev          = msg->buf.dev;
-      buf.st_ino          = msg->buf.ino;
-      buf.st_mode         = msg->buf.mode;
-      buf.st_nlink        = msg->buf.nlink ;
-      buf.st_uid          = msg->buf.uid ;
-      buf.st_gid          = msg->buf.gid;
-      buf.st_rdev         = msg->buf.rdev;
-      buf.st_size         = msg->buf.size;
-      buf.st_atim.tv_sec  = msg->buf.atim_sec;
-      buf.st_atim.tv_nsec = msg->buf.atim_nsec;
-      buf.st_mtim.tv_sec  = msg->buf.mtim_sec;
-      buf.st_mtim.tv_nsec = msg->buf.mtim_nsec;
-      buf.st_ctim.tv_sec  = msg->buf.ctim_sec;
-      buf.st_ctim.tv_nsec = msg->buf.ctim_nsec;
-      buf.st_blksize      = msg->buf.blksize;
-      buf.st_blocks       = msg->buf.blocks;
+      rpmsgfs_get_statbuf(&buf, &msg->buf);
 
       ret = file_fchstat(filep, &buf, msg->flags);
     }
@@ -883,6 +899,68 @@ out:
   return rpmsg_send(ept, msg, sizeof(*msg));
 }
 
+#ifdef CONFIG_FS_LINKS
+static int rpmsgfs_symlink_handler(FAR struct rpmsg_endpoint *ept,
+                                   FAR void *data, size_t len,
+                                   uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_symlink_s *msg = data;
+  FAR const char *target = msg->pathname;
+  FAR const char *linkpath = target + strlen(target) + 1;
+  int ret;
+
+  ret = symlink(target, linkpath);
+  msg->header.result = ret ? -get_errno() : 0;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_readlink_handler(FAR struct rpmsg_endpoint *ept,
+                                    FAR void *data, size_t len,
+                                    uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_readlink_s *msg = data;
+  ssize_t ret;
+  uint32_t space;
+
+  space = rpmsg_get_tx_buffer_size(ept);
+  ret = readlink(msg->pathname, msg->pathname, space - sizeof(*msg));
+  msg->header.result = ret < 0 ? -get_errno() : ret;
+  return rpmsg_send(ept, msg, sizeof(*msg) + (ret > 0 ? ret : 0));
+}
+
+static int rpmsgfs_link_handler(FAR struct rpmsg_endpoint *ept,
+                                FAR void *data, size_t len,
+                                uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_link_s *msg = data;
+  FAR const char *path1 = msg->pathname;
+  FAR const char *path2 = path1 + strlen(path1) + 1;
+  int ret;
+
+  ret = link(path1, path2);
+  msg->header.result = ret ? -get_errno() : 0;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+
+static int rpmsgfs_lstat_handler(FAR struct rpmsg_endpoint *ept,
+                                 FAR void *data, size_t len,
+                                 uint32_t src, FAR void *priv)
+{
+  FAR struct rpmsgfs_lstat_s *msg = data;
+  struct stat buf;
+  int ret;
+
+  ret = nx_stat(msg->pathname, &buf, 0);
+  if (ret >= 0)
+    {
+      rpmsgfs_set_statbuf(&msg->buf, &buf);
+    }
+
+  msg->header.result = ret;
+  return rpmsg_send(ept, msg, sizeof(*msg));
+}
+#endif
+
 static bool rpmsgfs_ns_match(FAR struct rpmsg_device *rdev,
                              FAR void *priv_, FAR const char *name,
                              uint32_t dest)

Reply via email to