From 41ec966941f38d0ce5bf1aa46e73cb9167cfa1a7 Mon Sep 17 00:00:00 2001 From: zhengyu16 Date: Tue, 2 Dec 2025 14:13:28 +0800 Subject: [PATCH] fs/rpmsgfs: add link, symlink, readlink and lstat support Implement link(), symlink(), readlink() and lstat() in rpmsgfs. Signed-off-by: zhengyu16 --- 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)