diff --git a/arch/arm/src/common/arm_hostfs.c b/arch/arm/src/common/arm_hostfs.c index 8545154248..d8ad1faeed 100644 --- a/arch/arm/src/common/arm_hostfs.c +++ b/arch/arm/src/common/arm_hostfs.c @@ -221,6 +221,11 @@ int host_fstat(int fd, struct stat *buf) return buf->st_size < 0 ? buf->st_size : 0; } +int host_fchstat(int fd, const struct stat *buf, int flags) +{ + return -ENOSYS; +} + int host_ftruncate(int fd, off_t length) { return -ENOSYS; @@ -315,3 +320,8 @@ int host_stat(const char *path, struct stat *buf) return ret; } + +int host_chstat(const char *path, const struct stat *buf, int flags) +{ + return -ENOSYS; +} diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in index 1a72b10f22..4b576d208c 100644 --- a/arch/sim/src/nuttx-names.in +++ b/arch/sim/src/nuttx-names.in @@ -34,6 +34,8 @@ NXSYMBOLS(__cxa_atexit) NXSYMBOLS(atexit) NXSYMBOLS(bind) NXSYMBOLS(calloc) +NXSYMBOLS(chmod) +NXSYMBOLS(chown) NXSYMBOLS(clock_gettime) NXSYMBOLS(close) NXSYMBOLS(closedir) @@ -41,10 +43,13 @@ NXSYMBOLS(connect) NXSYMBOLS(dlsym) NXSYMBOLS(dup) NXSYMBOLS(exit) +NXSYMBOLS(fchmod) +NXSYMBOLS(fchown) NXSYMBOLS(free) NXSYMBOLS(fstat) NXSYMBOLS(fsync) NXSYMBOLS(ftruncate) +NXSYMBOLS(futimens) NXSYMBOLS(if_nametoindex) NXSYMBOLS(ioctl) NXSYMBOLS(longjmp) @@ -105,5 +110,6 @@ NXSYMBOLS(tcgetattr) NXSYMBOLS(tcsetattr) NXSYMBOLS(unlink) NXSYMBOLS(usleep) +NXSYMBOLS(utimensat) NXSYMBOLS(write) NXSYMBOLS(writev) diff --git a/arch/sim/src/sim/up_hostfs.c b/arch/sim/src/sim/up_hostfs.c index a0333ba2ff..828f7e9803 100644 --- a/arch/sim/src/sim/up_hostfs.c +++ b/arch/sim/src/sim/up_hostfs.c @@ -312,6 +312,65 @@ int host_fstat(int fd, struct nuttx_stat_s *buf) return ret; } +/**************************************************************************** + * Name: host_fchstat + ****************************************************************************/ + +int host_fchstat(int fd, const struct nuttx_stat_s *buf, int flags) +{ + struct timespec times[2]; + int ret; + + if (flags & NUTTX_CH_STAT_MODE) + { + ret = fchmod(fd, buf->st_mode); + if (ret < 0) + { + return -errno; + } + } + + if (flags & (NUTTX_CH_STAT_UID | NUTTX_CH_STAT_GID)) + { + ret = fchown(fd, buf->st_uid, buf->st_gid); + if (ret < 0) + { + return -errno; + } + } + + if (flags & (NUTTX_CH_STAT_ATIME | NUTTX_CH_STAT_MTIME)) + { + if (flags & NUTTX_CH_STAT_ATIME) + { + times[0].tv_sec = buf->st_atim.tv_sec; + times[0].tv_nsec = buf->st_atim.tv_nsec; + } + else + { + times[0].tv_nsec = UTIME_OMIT; + } + + if (flags & NUTTX_CH_STAT_MTIME) + { + times[1].tv_sec = buf->st_mtim.tv_sec; + times[1].tv_nsec = buf->st_mtim.tv_nsec; + } + else + { + times[1].tv_nsec = UTIME_OMIT; + } + + ret = futimens(fd, times); + if (ret < 0) + { + return -errno; + } + } + + return 0; +} + /**************************************************************************** * Name: host_truncate ****************************************************************************/ @@ -538,3 +597,62 @@ int host_stat(const char *path, struct nuttx_stat_s *buf) host_stat_convert(&hostbuf, buf); return ret; } + +/**************************************************************************** + * Name: host_chstat + ****************************************************************************/ + +int host_chstat(const char *path, const struct nuttx_stat_s *buf, int flags) +{ + struct timespec times[2]; + int ret; + + if (flags & NUTTX_CH_STAT_MODE) + { + ret = chmod(path, buf->st_mode); + if (ret < 0) + { + return -errno; + } + } + + if (flags & (NUTTX_CH_STAT_UID | NUTTX_CH_STAT_GID)) + { + ret = chown(path, buf->st_uid, buf->st_gid); + if (ret < 0) + { + return -errno; + } + } + + if (flags & (NUTTX_CH_STAT_ATIME | NUTTX_CH_STAT_MTIME)) + { + if (flags & NUTTX_CH_STAT_ATIME) + { + times[0].tv_sec = buf->st_atim.tv_sec; + times[0].tv_nsec = buf->st_atim.tv_nsec; + } + else + { + times[0].tv_nsec = UTIME_OMIT; + } + + if (flags & NUTTX_CH_STAT_MTIME) + { + times[1].tv_sec = buf->st_mtim.tv_sec; + times[1].tv_nsec = buf->st_mtim.tv_nsec; + } + else + { + times[1].tv_nsec = UTIME_OMIT; + } + + ret = utimensat(AT_FDCWD, path, times, 0); + if (ret < 0) + { + return -errno; + } + } + + return 0; +} diff --git a/arch/xtensa/src/common/xtensa_hostfs.c b/arch/xtensa/src/common/xtensa_hostfs.c index d63682db21..fba8d3177b 100644 --- a/arch/xtensa/src/common/xtensa_hostfs.c +++ b/arch/xtensa/src/common/xtensa_hostfs.c @@ -153,6 +153,11 @@ int host_fstat(int fd, struct stat *buf) return 0; } +int host_fchstat(int fd, const struct stat *buf, int flags) +{ + return -ENOSYS; +} + int host_ftruncate(int fd, off_t length) { return -ENOSYS; @@ -225,3 +230,8 @@ int host_stat(const char *path, struct stat *buf) return ret; } + +int host_chstat(const char *path, const struct stat *buf, int flags) +{ + return -ENOSYS; +} diff --git a/fs/hostfs/hostfs.c b/fs/hostfs/hostfs.c index 2b117598d8..ca3033337a 100644 --- a/fs/hostfs/hostfs.c +++ b/fs/hostfs/hostfs.c @@ -72,6 +72,8 @@ static int hostfs_dup(FAR const struct file *oldp, FAR struct file *newp); static int hostfs_fstat(FAR const struct file *filep, FAR struct stat *buf); +static int hostfs_fchstat(FAR const struct file *filep, + FAR const struct stat *buf, int flags); static int hostfs_ftruncate(FAR struct file *filep, off_t length); @@ -102,6 +104,9 @@ static int hostfs_rename(FAR struct inode *mountpt, FAR const char *newrelpath); static int hostfs_stat(FAR struct inode *mountpt, FAR const char *relpath, FAR struct stat *buf); +static int hostfs_chstat(FAR struct inode *mountpt, + FAR const char *relpath, + FAR const struct stat *buf, int flags); /**************************************************************************** * Private Data @@ -131,7 +136,7 @@ const struct mountpt_operations hostfs_operations = hostfs_sync, /* sync */ hostfs_dup, /* dup */ hostfs_fstat, /* fstat */ - NULL, /* fchstat */ + hostfs_fchstat, /* fchstat */ hostfs_ftruncate, /* ftruncate */ hostfs_opendir, /* opendir */ @@ -148,7 +153,7 @@ const struct mountpt_operations hostfs_operations = hostfs_rmdir, /* rmdir */ hostfs_rename, /* rename */ hostfs_stat, /* stat */ - NULL /* chstat */ + hostfs_chstat, /* chstat */ }; /**************************************************************************** @@ -739,6 +744,52 @@ static int hostfs_fstat(FAR const struct file *filep, FAR struct stat *buf) return ret; } +/**************************************************************************** + * Name: hostfs_fchstat + * + * Description: + * Change information about an open file associated with the file + * descriptor 'fd'. + * + ****************************************************************************/ + +static int hostfs_fchstat(FAR const struct file *filep, + FAR const struct stat *buf, int flags) +{ + FAR struct inode *inode; + FAR struct hostfs_mountpt_s *fs; + FAR struct hostfs_ofile_s *hf; + int ret = OK; + + /* Sanity checks */ + + DEBUGASSERT(filep != NULL && buf != NULL); + + /* Recover our private data from the struct file instance */ + + DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL); + hf = filep->f_priv; + inode = filep->f_inode; + + fs = inode->i_private; + DEBUGASSERT(fs != NULL); + + /* Take the semaphore */ + + ret = hostfs_semtake(fs); + if (ret < 0) + { + return ret; + } + + /* Call the host to perform the change */ + + ret = host_fchstat(hf->fd, buf, flags); + + hostfs_semgive(fs); + return ret; +} + /**************************************************************************** * Name: hostfs_ftruncate * @@ -1329,6 +1380,46 @@ static int hostfs_stat(FAR struct inode *mountpt, FAR const char *relpath, return ret; } +/**************************************************************************** + * Name: hostfs_chstat + * + * Description: Change information about a file or directory + * + ****************************************************************************/ + +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]; + int ret; + + /* Sanity checks */ + + DEBUGASSERT(mountpt && mountpt->i_private); + + /* Get the mountpoint private data from the inode structure */ + + fs = mountpt->i_private; + + ret = hostfs_semtake(fs); + if (ret < 0) + { + return ret; + } + + /* Append to the host's root directory */ + + hostfs_mkpath(fs, relpath, path, sizeof(path)); + + /* Call the host FS to do the chstat operation */ + + ret = host_chstat(path, buf, flags); + + hostfs_semgive(fs); + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/fs/hostfs/hostfs_rpmsg.c b/fs/hostfs/hostfs_rpmsg.c index 0b724e5dad..4e5be7d863 100644 --- a/fs/hostfs/hostfs_rpmsg.c +++ b/fs/hostfs/hostfs_rpmsg.c @@ -111,6 +111,8 @@ static const rpmsg_ept_cb g_hostfs_rpmsg_handler[] = [HOSTFS_RPMSG_RMDIR] = hostfs_rpmsg_default_handler, [HOSTFS_RPMSG_RENAME] = hostfs_rpmsg_default_handler, [HOSTFS_RPMSG_STAT] = hostfs_rpmsg_stat_handler, + [HOSTFS_RPMSG_FCHSTAT] = hostfs_rpmsg_default_handler, + [HOSTFS_RPMSG_CHSTAT] = hostfs_rpmsg_default_handler, }; /**************************************************************************** @@ -721,6 +723,45 @@ int host_stat(FAR const char *path, FAR struct stat *buf) (struct hostfs_rpmsg_header_s *)msg, len, buf); } +int host_fchstat(int fd, const struct stat *buf, int flags) +{ + struct hostfs_rpmsg_fchstat_s msg = + { + .flags = flags, + .buf = *buf, + .fd = fd, + }; + + return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_FCHSTAT, true, + (struct hostfs_rpmsg_header_s *)&msg, sizeof(msg), NULL); +} + +int host_chstat(FAR const char *path, const FAR struct stat *buf, int flags) +{ + FAR struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg; + FAR struct hostfs_rpmsg_chstat_s *msg; + uint32_t space; + size_t len; + + len = sizeof(*msg); + len += B2C(strlen(path) + 1); + + msg = rpmsg_get_tx_payload_buffer(&priv->ept, &space, true); + if (!msg) + { + return -ENOMEM; + } + + DEBUGASSERT(len <= space); + + msg->flags = flags; + memcpy(&msg->buf, buf, sizeof(*buf)); + cstr2bstr(msg->pathname, path); + + return hostfs_rpmsg_send_recv(HOSTFS_RPMSG_CHSTAT, false, + (struct hostfs_rpmsg_header_s *)msg, len, NULL); +} + int hostfs_rpmsg_init(FAR const char *cpuname) { struct hostfs_rpmsg_s *priv = &g_hostfs_rpmsg; diff --git a/fs/hostfs/hostfs_rpmsg.h b/fs/hostfs/hostfs_rpmsg.h index b5b98228eb..9f11a1d499 100644 --- a/fs/hostfs/hostfs_rpmsg.h +++ b/fs/hostfs/hostfs_rpmsg.h @@ -58,6 +58,8 @@ #define HOSTFS_RPMSG_RMDIR 18 #define HOSTFS_RPMSG_RENAME 19 #define HOSTFS_RPMSG_STAT 20 +#define HOSTFS_RPMSG_FCHSTAT 21 +#define HOSTFS_RPMSG_CHSTAT 22 /**************************************************************************** * Public Types @@ -179,4 +181,23 @@ begin_packed_struct struct hostfs_rpmsg_mkdir_s #define hostfs_rpmsg_rename_s hostfs_rpmsg_opendir_s #define hostfs_rpmsg_stat_s hostfs_rpmsg_fstat_s +begin_packed_struct struct hostfs_rpmsg_fchstat_s +{ + struct hostfs_rpmsg_header_s header; + int32_t flags; + union + { + struct stat buf; + uint32_t reserved[16]; + }; + + union + { + int32_t fd; + char pathname[0]; + }; +} end_packed_struct; + +#define hostfs_rpmsg_chstat_s hostfs_rpmsg_fchstat_s + #endif /* __FS_HOSTFS_HOSTFS_RPMSG_H */ diff --git a/fs/hostfs/hostfs_rpmsg_server.c b/fs/hostfs/hostfs_rpmsg_server.c index 58d7a2bc40..9e8a68b8d4 100644 --- a/fs/hostfs/hostfs_rpmsg_server.c +++ b/fs/hostfs/hostfs_rpmsg_server.c @@ -116,6 +116,12 @@ static int hostfs_rpmsg_rename_handler(FAR struct rpmsg_endpoint *ept, static int hostfs_rpmsg_stat_handler(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv); +static int hostfs_rpmsg_fchstat_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); +static int hostfs_rpmsg_chstat_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv); static void hostfs_rpmsg_ns_bind(FAR struct rpmsg_device *rdev, FAR void *priv_, FAR const char *name, @@ -151,6 +157,8 @@ static const rpmsg_ept_cb g_hostfs_rpmsg_handler[] = [HOSTFS_RPMSG_RMDIR] = hostfs_rpmsg_rmdir_handler, [HOSTFS_RPMSG_RENAME] = hostfs_rpmsg_rename_handler, [HOSTFS_RPMSG_STAT] = hostfs_rpmsg_stat_handler, + [HOSTFS_RPMSG_FCHSTAT] = hostfs_rpmsg_fchstat_handler, + [HOSTFS_RPMSG_CHSTAT] = hostfs_rpmsg_chstat_handler, }; /**************************************************************************** @@ -704,6 +712,87 @@ static int hostfs_rpmsg_stat_handler(FAR struct rpmsg_endpoint *ept, return rpmsg_send(ept, msg, sizeof(*msg)); } +static int hostfs_rpmsg_fchstat_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct hostfs_rpmsg_fchstat_s *msg = data; + FAR struct file *filep; + int ret = -ENOENT; + struct stat buf; + + filep = hostfs_rpmsg_get_file(priv, msg->fd); + if (filep != NULL) + { + buf = msg->buf; + ret = file_fchstat(filep, &buf, msg->flags); + } + + msg->header.result = ret; + return rpmsg_send(ept, msg, sizeof(*msg)); +} + +static int hostfs_rpmsg_chstat_handler(FAR struct rpmsg_endpoint *ept, + FAR void *data, size_t len, + uint32_t src, FAR void *priv) +{ + FAR struct hostfs_rpmsg_chstat_s *msg = data; + struct timespec times[2]; + int ret = 0; + + if (msg->flags & CH_STAT_MODE) + { + ret = chmod(msg->pathname, msg->buf.st_mode); + if (ret < 0) + { + ret = -get_errno(); + goto out; + } + } + + if (msg->flags & (CH_STAT_UID | CH_STAT_GID)) + { + ret = chown(msg->pathname, msg->buf.st_uid, msg->buf.st_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] = msg->buf.st_atim; + } + else + { + times[0].tv_nsec = UTIME_OMIT; + } + + if (msg->flags & CH_STAT_MTIME) + { + times[1] = msg->buf.st_mtim; + } + else + { + 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 void hostfs_rpmsg_ns_bind(FAR struct rpmsg_device *rdev, FAR void *priv_, FAR const char *name, uint32_t dest) diff --git a/include/nuttx/fs/hostfs.h b/include/nuttx/fs/hostfs.h index bf009ed6c9..cd98ba3994 100644 --- a/include/nuttx/fs/hostfs.h +++ b/include/nuttx/fs/hostfs.h @@ -87,9 +87,13 @@ #define NUTTX_O_RDWR (NUTTX_O_RDONLY | NUTTX_O_WRONLY) -/* Should match definition in include/limits.h */ +/* Should match definition in include/nuttx/fs/fs.h */ -#define NUTTX_NAME_MAX CONFIG_NAME_MAX +#define NUTTX_CH_STAT_MODE (1 << 0) +#define NUTTX_CH_STAT_UID (1 << 1) +#define NUTTX_CH_STAT_GID (1 << 2) +#define NUTTX_CH_STAT_ATIME (1 << 3) +#define NUTTX_CH_STAT_MTIME (1 << 4) #endif /* __SIM__ */ @@ -132,8 +136,8 @@ struct nuttx_timespec struct nuttx_dirent_s { - uint8_t d_type; /* type of file */ - char d_name[NUTTX_NAME_MAX + 1]; /* filename */ + uint8_t d_type; /* type of file */ + char d_name[CONFIG_NAME_MAX + 1]; /* filename */ }; /* These must exactly match the definition from include/sys/statfs.h: */ @@ -185,6 +189,8 @@ int host_ioctl(int fd, int request, unsigned long arg); void host_sync(int fd); int host_dup(int fd); int host_fstat(int fd, struct nuttx_stat_s *buf); +int host_fchstat(int fd, const struct nuttx_stat_s *buf, + int flags); int host_ftruncate(int fd, nuttx_off_t length); void *host_opendir(const char *name); int host_readdir(void *dirp, struct nuttx_dirent_s *entry); @@ -196,6 +202,8 @@ int host_mkdir(const char *pathname, mode_t mode); int host_rmdir(const char *pathname); 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); #else int host_open(const char *pathname, int flags, int mode); int host_close(int fd); @@ -206,6 +214,7 @@ int host_ioctl(int fd, int request, unsigned long arg); void host_sync(int fd); int host_dup(int fd); int host_fstat(int fd, struct stat *buf); +int host_fchstat(int fd, const struct stat *buf, int flags); int host_ftruncate(int fd, off_t length); void *host_opendir(const char *name); int host_readdir(void *dirp, struct dirent *entry); @@ -217,7 +226,8 @@ int host_mkdir(const char *pathname, mode_t mode); int host_rmdir(const char *pathname); 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); #endif /* __SIM__ */ #endif /* __INCLUDE_NUTTX_FS_HOSTFS_H */