| /**************************************************************************** |
| * fs/rpmsgfs/rpmsgfs_server.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <dirent.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <errno.h> |
| |
| #include <nuttx/kmalloc.h> |
| #include <nuttx/mutex.h> |
| #include <nuttx/fs/fs.h> |
| #include <nuttx/rptun/openamp.h> |
| |
| #include "rpmsgfs.h" |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| struct rpmsgfs_server_s |
| { |
| struct rpmsg_endpoint ept; |
| FAR struct file **files; |
| FAR void **dirs; |
| int file_rows; |
| int dir_nums; |
| mutex_t lock; |
| }; |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| static int rpmsgfs_open_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_close_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_read_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_write_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_lseek_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_ioctl_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_sync_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_dup_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_fstat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_ftruncate_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_opendir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_readdir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_rewinddir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_closedir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_statfs_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_unlink_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_mkdir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_rmdir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_rename_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_fchstat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| static int rpmsgfs_chstat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv); |
| |
| static bool rpmsgfs_ns_match(FAR struct rpmsg_device *rdev, |
| FAR void *priv_, FAR const char *name, |
| uint32_t dest); |
| static void rpmsgfs_ns_bind(FAR struct rpmsg_device *rdev, |
| FAR void *priv_, FAR const char *name, |
| uint32_t dest); |
| static void rpmsgfs_ns_unbind(FAR struct rpmsg_endpoint *ept); |
| static int rpmsgfs_ept_cb(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, uint32_t src, |
| FAR void *priv); |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| static const rpmsg_ept_cb g_rpmsgfs_handler[] = |
| { |
| [RPMSGFS_OPEN] = rpmsgfs_open_handler, |
| [RPMSGFS_CLOSE] = rpmsgfs_close_handler, |
| [RPMSGFS_READ] = rpmsgfs_read_handler, |
| [RPMSGFS_WRITE] = rpmsgfs_write_handler, |
| [RPMSGFS_LSEEK] = rpmsgfs_lseek_handler, |
| [RPMSGFS_IOCTL] = rpmsgfs_ioctl_handler, |
| [RPMSGFS_SYNC] = rpmsgfs_sync_handler, |
| [RPMSGFS_DUP] = rpmsgfs_dup_handler, |
| [RPMSGFS_FSTAT] = rpmsgfs_fstat_handler, |
| [RPMSGFS_FTRUNCATE] = rpmsgfs_ftruncate_handler, |
| [RPMSGFS_OPENDIR] = rpmsgfs_opendir_handler, |
| [RPMSGFS_READDIR] = rpmsgfs_readdir_handler, |
| [RPMSGFS_REWINDDIR] = rpmsgfs_rewinddir_handler, |
| [RPMSGFS_CLOSEDIR] = rpmsgfs_closedir_handler, |
| [RPMSGFS_STATFS] = rpmsgfs_statfs_handler, |
| [RPMSGFS_UNLINK] = rpmsgfs_unlink_handler, |
| [RPMSGFS_MKDIR] = rpmsgfs_mkdir_handler, |
| [RPMSGFS_RMDIR] = rpmsgfs_rmdir_handler, |
| [RPMSGFS_RENAME] = rpmsgfs_rename_handler, |
| [RPMSGFS_STAT] = rpmsgfs_stat_handler, |
| [RPMSGFS_FCHSTAT] = rpmsgfs_fchstat_handler, |
| [RPMSGFS_CHSTAT] = rpmsgfs_chstat_handler, |
| }; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| static int rpmsgfs_attach_file(FAR struct rpmsgfs_server_s *priv, |
| FAR struct file *filep) |
| { |
| FAR struct file **tmp; |
| int ret; |
| int i; |
| int j; |
| |
| nxmutex_lock(&priv->lock); |
| |
| for (i = 0; i < priv->file_rows; i++) |
| { |
| for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++) |
| { |
| if (priv->files[i][j].f_inode == NULL) |
| { |
| memcpy(&priv->files[i][j], filep, sizeof(*filep)); |
| ret = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + j; |
| goto out; |
| } |
| } |
| } |
| |
| tmp = kmm_realloc(priv->files, sizeof(FAR struct file *) * (i + 1)); |
| DEBUGASSERT(tmp); |
| if (tmp == NULL) |
| { |
| ret = -ENFILE; |
| goto out; |
| } |
| |
| tmp[i] = kmm_zalloc(sizeof(struct file) * |
| CONFIG_NFILE_DESCRIPTORS_PER_BLOCK); |
| DEBUGASSERT(tmp[i]); |
| if (tmp[i] == NULL) |
| { |
| kmm_free(tmp); |
| ret = -ENFILE; |
| goto out; |
| } |
| |
| priv->files = tmp; |
| priv->file_rows++; |
| |
| memcpy(&priv->files[i][0], filep, sizeof(*filep)); |
| ret = i * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; |
| |
| out: |
| nxmutex_unlock(&priv->lock); |
| return ret; |
| } |
| |
| static int rpmsgfs_detach_file(FAR struct rpmsgfs_server_s *priv, |
| int fd, FAR struct file *filep) |
| { |
| struct file *tfilep; |
| |
| if (fd < 0 || fd >= priv->file_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK) |
| { |
| return -EBADF; |
| } |
| |
| nxmutex_lock(&priv->lock); |
| tfilep = &priv->files[fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK] |
| [fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]; |
| memcpy(filep, tfilep, sizeof(*filep)); |
| memset(tfilep, 0, sizeof(*tfilep)); |
| nxmutex_unlock(&priv->lock); |
| |
| return 0; |
| } |
| |
| static FAR struct file *rpmsgfs_get_file( |
| FAR struct rpmsgfs_server_s *priv, |
| int fd) |
| { |
| FAR struct file *filep; |
| |
| if (fd < 0 || fd >= priv->file_rows * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK) |
| { |
| return NULL; |
| } |
| |
| nxmutex_lock(&priv->lock); |
| filep = &priv->files[fd / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK] |
| [fd % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]; |
| nxmutex_unlock(&priv->lock); |
| |
| return filep; |
| } |
| |
| static int rpmsgfs_attach_dir(FAR struct rpmsgfs_server_s *priv, |
| FAR void *dir) |
| { |
| FAR void **tmp; |
| int i; |
| |
| nxmutex_lock(&priv->lock); |
| for (i = 1; i < priv->dir_nums; i++) |
| { |
| if (priv->dirs[i] == NULL) |
| { |
| priv->dirs[i] = dir; |
| nxmutex_unlock(&priv->lock); |
| return i; |
| } |
| } |
| |
| tmp = kmm_realloc(priv->dirs, sizeof(FAR void *) * |
| (priv->dir_nums + CONFIG_NFILE_DESCRIPTORS_PER_BLOCK)); |
| DEBUGASSERT(tmp); |
| if (tmp == NULL) |
| { |
| nxmutex_unlock(&priv->lock); |
| return -ENOMEM; |
| } |
| |
| memset(&tmp[priv->dir_nums], 0, sizeof(FAR void *) * |
| CONFIG_NFILE_DESCRIPTORS_PER_BLOCK); |
| |
| priv->dirs = tmp; |
| priv->dir_nums += CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; |
| |
| priv->dirs[i] = dir; |
| nxmutex_unlock(&priv->lock); |
| return i; |
| } |
| |
| static void *rpmsgfs_detach_dir(FAR struct rpmsgfs_server_s *priv, |
| int fd) |
| { |
| FAR void *dir = NULL; |
| |
| if (fd >= 1 && fd < priv->dir_nums) |
| { |
| nxmutex_lock(&priv->lock); |
| dir = priv->dirs[fd]; |
| priv->dirs[fd] = NULL; |
| nxmutex_unlock(&priv->lock); |
| } |
| |
| return dir; |
| } |
| |
| static FAR void *rpmsgfs_get_dir( |
| FAR struct rpmsgfs_server_s *priv, |
| int fd) |
| { |
| FAR void *dir = NULL; |
| |
| if (fd >= 1 && fd < priv->dir_nums) |
| { |
| nxmutex_lock(&priv->lock); |
| dir = priv->dirs[fd]; |
| nxmutex_unlock(&priv->lock); |
| } |
| |
| return dir; |
| } |
| |
| static int rpmsgfs_open_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_open_s *msg = data; |
| struct file file; |
| int ret; |
| |
| ret = file_open(&file, msg->pathname, msg->flags, msg->mode); |
| if (ret >= 0) |
| { |
| ret = rpmsgfs_attach_file(priv, &file); |
| if (ret < 0) |
| { |
| file_close(&file); |
| } |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_close_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_close_s *msg = data; |
| struct file file; |
| int ret; |
| |
| ret = rpmsgfs_detach_file(priv, msg->fd, &file); |
| if (ret >= 0) |
| { |
| ret = file_close(&file); |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_read_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_read_s *msg = data; |
| FAR struct rpmsgfs_read_s *rsp; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| size_t read = 0; |
| uint32_t space; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| |
| while (read < msg->count) |
| { |
| rsp = rpmsg_get_tx_payload_buffer(ept, &space, true); |
| if (rsp == NULL) |
| { |
| return -ENOMEM; |
| } |
| |
| *rsp = *msg; |
| |
| space -= sizeof(*msg); |
| if (space > msg->count - read) |
| { |
| space = msg->count - read; |
| } |
| |
| if (filep != NULL) |
| { |
| ret = file_read(filep, rsp->buf, space); |
| } |
| |
| rsp->header.result = ret; |
| rpmsg_send_nocopy(ept, rsp, (ret < 0 ? 0 : ret) + sizeof(*rsp)); |
| |
| if (ret <= 0) |
| { |
| break; |
| } |
| |
| read += ret; |
| } |
| |
| return 0; |
| } |
| |
| static int rpmsgfs_write_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_write_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| size_t written = 0; |
| |
| while (written < msg->count) |
| { |
| ret = file_write(filep, msg->buf + written, msg->count - written); |
| if (ret < 0) |
| { |
| break; |
| } |
| |
| written += ret; |
| } |
| } |
| |
| if (msg->header.cookie != 0) |
| { |
| msg->header.result = ret; |
| rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| return 0; |
| } |
| |
| static int rpmsgfs_lseek_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_lseek_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| ret = file_seek(filep, msg->offset, msg->whence); |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_ioctl_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_ioctl_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| ret = file_ioctl(filep, msg->request, msg->arglen > 0 ? |
| (unsigned long)msg->buf : msg->arg); |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, len); |
| } |
| |
| static int rpmsgfs_sync_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_sync_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| ret = file_fsync(filep); |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_dup_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_dup_s *msg = data; |
| FAR struct file *filep; |
| struct file newfile; |
| int ret = -ENOENT; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| ret = file_dup2(filep, &newfile); |
| if (ret >= 0) |
| { |
| ret = rpmsgfs_attach_file(priv, &newfile); |
| if (ret < 0) |
| { |
| file_close(&newfile); |
| } |
| } |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_fstat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_fstat_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| struct stat buf; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| 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; |
| } |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_ftruncate_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_ftruncate_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| |
| filep = rpmsgfs_get_file(priv, msg->fd); |
| if (filep != NULL) |
| { |
| ret = file_truncate(filep, msg->length); |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_opendir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_opendir_s *msg = data; |
| FAR void *dir; |
| int ret = -ENOENT; |
| |
| dir = opendir(msg->pathname); |
| if (dir) |
| { |
| ret = rpmsgfs_attach_dir(priv, dir); |
| if (ret < 0) |
| { |
| closedir(dir); |
| } |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_readdir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_readdir_s *msg = data; |
| FAR struct dirent *entry; |
| int ret = -ENOENT; |
| FAR void *dir; |
| size_t size; |
| |
| dir = rpmsgfs_get_dir(priv, msg->fd); |
| if (dir) |
| { |
| entry = readdir(dir); |
| if (entry) |
| { |
| size = MIN(rpmsg_get_tx_buffer_size(ept->rdev), |
| rpmsg_get_rx_buffer_size(ept->rdev)); |
| size = MIN(size - len, strlen(entry->d_name) + 1); |
| msg->type = entry->d_type; |
| strlcpy(msg->name, entry->d_name, size); |
| len += size; |
| ret = 0; |
| } |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, len); |
| } |
| |
| static int rpmsgfs_rewinddir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_rewinddir_s *msg = data; |
| int ret = -ENOENT; |
| FAR void *dir; |
| |
| dir = rpmsgfs_get_dir(priv, msg->fd); |
| if (dir) |
| { |
| rewinddir(dir); |
| ret = 0; |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_closedir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_closedir_s *msg = data; |
| int ret = -ENOENT; |
| FAR void *dir; |
| |
| dir = rpmsgfs_detach_dir(priv, msg->fd); |
| if (dir) |
| { |
| ret = closedir(dir) ? -get_errno() : 0; |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_statfs_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_statfs_s *msg = data; |
| struct statfs buf; |
| int ret; |
| |
| ret = statfs(msg->pathname, &buf); |
| if (ret) |
| { |
| ret = -get_errno(); |
| } |
| else |
| { |
| msg->type = buf.f_type; |
| msg->namelen = buf.f_namelen; |
| msg->bsize = buf.f_bsize; |
| msg->blocks = buf.f_blocks; |
| msg->bfree = buf.f_bfree; |
| msg->bavail = buf.f_bavail; |
| msg->files = buf.f_files; |
| msg->ffree = buf.f_ffree; |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_unlink_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_unlink_s *msg = data; |
| |
| msg->header.result = nx_unlink(msg->pathname); |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_mkdir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_mkdir_s *msg = data; |
| int ret; |
| |
| ret = mkdir(msg->pathname, msg->mode); |
| msg->header.result = ret ? -get_errno() : 0; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_rmdir_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_rmdir_s *msg = data; |
| int ret; |
| |
| ret = rmdir(msg->pathname); |
| msg->header.result = ret ? -get_errno() : 0; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_rename_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_rename_s *msg = data; |
| FAR char *newpath; |
| size_t oldlen; |
| int ret; |
| |
| oldlen = (strlen(msg->pathname) + 1 + 0x7) & ~0x7; |
| newpath = msg->pathname + oldlen; |
| |
| ret = rename(msg->pathname, newpath); |
| msg->header.result = ret ? -get_errno() : 0; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_stat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_stat_s *msg = data; |
| struct stat buf; |
| int ret; |
| |
| 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; |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_fchstat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_fchstat_s *msg = data; |
| FAR struct file *filep; |
| int ret = -ENOENT; |
| struct stat buf; |
| |
| 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; |
| |
| ret = file_fchstat(filep, &buf, msg->flags); |
| } |
| |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static int rpmsgfs_chstat_handler(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, |
| uint32_t src, FAR void *priv) |
| { |
| FAR struct rpmsgfs_chstat_s *msg = data; |
| struct timespec times[2]; |
| int ret = 0; |
| |
| if (msg->flags & CH_STAT_MODE) |
| { |
| ret = chmod(msg->pathname, msg->buf.mode); |
| if (ret < 0) |
| { |
| ret = -get_errno(); |
| goto out; |
| } |
| } |
| |
| if (msg->flags & (CH_STAT_UID | CH_STAT_GID)) |
| { |
| ret = chown(msg->pathname, msg->buf.uid, msg->buf.gid); |
| if (ret < 0) |
| { |
| ret = -get_errno(); |
| goto out; |
| } |
| } |
| |
| if (msg->flags & (CH_STAT_ATIME | CH_STAT_MTIME)) |
| { |
| if (msg->flags & CH_STAT_ATIME) |
| { |
| times[0].tv_sec = msg->buf.atim_sec; |
| times[0].tv_nsec = msg->buf.atim_nsec; |
| } |
| else |
| { |
| times[0].tv_sec = 0; |
| times[0].tv_nsec = UTIME_OMIT; |
| } |
| |
| if (msg->flags & CH_STAT_MTIME) |
| { |
| times[1].tv_sec = msg->buf.mtim_sec; |
| times[1].tv_nsec = msg->buf.mtim_nsec; |
| } |
| else |
| { |
| times[1].tv_sec = 0; |
| times[1].tv_nsec = UTIME_OMIT; |
| } |
| |
| ret = utimens(msg->pathname, times); |
| if (ret < 0) |
| { |
| ret = -get_errno(); |
| goto out; |
| } |
| } |
| |
| out: |
| msg->header.result = ret; |
| return rpmsg_send(ept, msg, sizeof(*msg)); |
| } |
| |
| static bool rpmsgfs_ns_match(FAR struct rpmsg_device *rdev, |
| FAR void *priv_, FAR const char *name, |
| uint32_t dest) |
| { |
| return !strncmp(name, RPMSGFS_NAME_PREFIX, strlen(RPMSGFS_NAME_PREFIX)); |
| } |
| |
| static void rpmsgfs_ns_bind(FAR struct rpmsg_device *rdev, |
| FAR void *priv_, FAR const char *name, |
| uint32_t dest) |
| { |
| FAR struct rpmsgfs_server_s *priv; |
| int ret; |
| |
| priv = kmm_zalloc(sizeof(*priv)); |
| if (!priv) |
| { |
| return; |
| } |
| |
| priv->ept.priv = priv; |
| nxmutex_init(&priv->lock); |
| |
| ret = rpmsg_create_ept(&priv->ept, rdev, name, |
| RPMSG_ADDR_ANY, dest, |
| rpmsgfs_ept_cb, rpmsgfs_ns_unbind); |
| if (ret) |
| { |
| nxmutex_destroy(&priv->lock); |
| kmm_free(priv); |
| } |
| } |
| |
| static void rpmsgfs_ns_unbind(FAR struct rpmsg_endpoint *ept) |
| { |
| FAR struct rpmsgfs_server_s *priv = ept->priv; |
| int i; |
| int j; |
| |
| for (i = 0; i < priv->file_rows; i++) |
| { |
| for (j = 0; j < CONFIG_NFILE_DESCRIPTORS_PER_BLOCK; j++) |
| { |
| if (priv->files[i][j].f_inode) |
| { |
| file_close(&priv->files[i][j]); |
| } |
| } |
| |
| kmm_free(priv->files[i]); |
| } |
| |
| for (i = 0; i < priv->dir_nums; i++) |
| { |
| if (priv->dirs[i]) |
| { |
| closedir(priv->dirs[i]); |
| } |
| } |
| |
| rpmsg_destroy_ept(&priv->ept); |
| nxmutex_destroy(&priv->lock); |
| |
| kmm_free(priv->files); |
| kmm_free(priv->dirs); |
| kmm_free(priv); |
| } |
| |
| static int rpmsgfs_ept_cb(FAR struct rpmsg_endpoint *ept, |
| FAR void *data, size_t len, uint32_t src, |
| FAR void *priv) |
| { |
| struct rpmsgfs_header_s *header = data; |
| uint32_t command = header->command; |
| |
| if (command < nitems(g_rpmsgfs_handler)) |
| { |
| return g_rpmsgfs_handler[command](ept, data, len, src, priv); |
| } |
| |
| return -EINVAL; |
| } |
| |
| int rpmsgfs_server_init(void) |
| { |
| return rpmsg_register_callback(NULL, |
| NULL, |
| NULL, |
| rpmsgfs_ns_match, |
| rpmsgfs_ns_bind); |
| } |