diff --git a/os/sb/common/sbsysc.h b/os/sb/common/sbsysc.h index 3af308227..bd7992b1a 100644 --- a/os/sb/common/sbsysc.h +++ b/os/sb/common/sbsysc.h @@ -69,6 +69,7 @@ #define SB_POSIX_RENAME 13 #define SB_POSIX_MKDIR 14 #define SB_POSIX_RMDIR 15 +#define SB_POSIX_STAT 16 /** @} */ /*===========================================================================*/ diff --git a/os/sb/host/sbposix.c b/os/sb/host/sbposix.c index b63c5a465..a2d76e812 100644 --- a/os/sb/host/sbposix.c +++ b/os/sb/host/sbposix.c @@ -70,6 +70,30 @@ static msg_t create_descriptor(sb_ioblock_t *iop, /* Module exported functions. */ /*===========================================================================*/ +int sb_posix_stat(const char *path, struct stat *statbuf) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + msg_t ret; + vfs_stat_t vstat; + + if (sb_check_string(sbp, (void *)path, VFS_CFG_PATHLEN_MAX + 1) == (size_t)0) { + return CH_RET_EFAULT; + } + + if (!sb_is_valid_write_range(sbp, (void *)statbuf, sizeof (struct stat))) { + return CH_RET_EFAULT; + } + + ret = (int)vfsDrvStat(sbp->config->vfs_driver, path, &vstat); + if (!CH_RET_IS_ERROR(ret)) { + memset((void *)statbuf, 0, sizeof (struct stat)); + statbuf->st_mode = (mode_t)vstat.mode; + statbuf->st_size = (off_t)vstat.size; + statbuf->st_nlink = 1; + } + + return ret; +} + int sb_posix_open(const char *path, int flags) { sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; vfs_node_c *np = NULL; diff --git a/os/sb/user/sbuser.h b/os/sb/user/sbuser.h index 8ae8b279d..4b6ce8f65 100644 --- a/os/sb/user/sbuser.h +++ b/os/sb/user/sbuser.h @@ -209,6 +209,19 @@ extern "C" { /* Module inline functions. */ /*===========================================================================*/ +/** + * @brief Posix-style file status. + * + * @param[in] pathname file to be examined + * @param[in] statbuf pointer to a @p stat structure + * @return Operation result. + */ +static inline int sbStat(const char *pathname, struct stat *statbuf) { + + __syscall3r(0, SB_POSIX_STAT, pathname, statbuf); + return (int)r0; +} + /** * @brief Posix-style file open. * @@ -260,11 +273,10 @@ static inline int sbDup2(int oldfd, int newfd) { } /** - * @brief Posix-style file file status. + * @brief Posix-style file status. * * @param[in] fd file descriptor * @param[in] statbuf pointer to a @p stat structure - * @param[in] whence operation mode * @return Operation result. */ static inline int sbFstat(int fd, struct stat *statbuf) { diff --git a/os/vfs/drivers/fatfs/drvfatfs.c b/os/vfs/drivers/fatfs/drvfatfs.c index 4b32dfb17..5f4e03b70 100644 --- a/os/vfs/drivers/fatfs/drvfatfs.c +++ b/os/vfs/drivers/fatfs/drvfatfs.c @@ -112,6 +112,7 @@ typedef struct vfs_fatfs_file_node { static msg_t drv_set_cwd(void *instance, const char *path); static msg_t drv_get_cwd(void *instance, char *buf, size_t size); +static msg_t drv_stat(void *instance, const char *path, vfs_stat_t *sp); static msg_t drv_open_dir(void *instance, const char *path, vfs_directory_node_c **vdnpp); @@ -127,6 +128,7 @@ msg_t drv_rmdir(void *instance, const char *path); static const struct vfs_fatfs_driver_vmt driver_vmt = { .set_cwd = drv_set_cwd, .get_cwd = drv_get_cwd, + .stat = drv_stat, .open_dir = drv_open_dir, .open_file = drv_open_file, .unlink = drv_unlink, @@ -350,10 +352,46 @@ static msg_t drv_get_cwd(void *instance, char *buf, size_t size) { #endif } +static msg_t drv_stat(void *instance, const char *path, vfs_stat_t *sp) { + msg_t ret; + + (void)instance; + + do { + FRESULT res; + FILINFO *fip; + + fip = (FILINFO *)chPoolAlloc(&vfs_fatfs_driver_static.info_nodes_pool); + if (fip != NULL) { + + res = f_stat((const TCHAR *)path, fip); + if (res == FR_OK) { + + sp->mode = translate_mode(fip->fattrib); + sp->size = (vfs_offset_t)fip->fsize; + + ret = CH_RET_SUCCESS; + } + else { + ret = translate_error(res); + } + + chPoolFree(&vfs_fatfs_driver_static.info_nodes_pool, (void *)fip); + } + else { + ret = CH_RET_ENOMEM; + break; + } + } + while (false); + + return ret; +} + static msg_t drv_open_dir(void *instance, const char *path, vfs_directory_node_c **vdnpp) { - msg_t err; + msg_t ret; do { vfs_fatfs_driver_c *drvp = (vfs_fatfs_driver_c *)instance; @@ -363,7 +401,7 @@ static msg_t drv_open_dir(void *instance, ffdnp = chPoolAlloc(&vfs_fatfs_driver_static.dir_nodes_pool); if (ffdnp != NULL) { - res = f_opendir(&ffdnp->dir, (TCHAR *)path); + res = f_opendir(&ffdnp->dir, (const TCHAR *)path); if (res == FR_OK) { /* Node object initialization.*/ @@ -372,25 +410,29 @@ static msg_t drv_open_dir(void *instance, ffdnp->mode = translate_mode(ffdnp->dir.obj.attr); *vdnpp = (vfs_directory_node_c *)ffdnp; - err = CH_RET_SUCCESS; + ret = CH_RET_SUCCESS; break; } chPoolFree(&vfs_fatfs_driver_static.dir_nodes_pool, (void *)ffdnp); } + else { + ret = CH_RET_ENOMEM; + break; + } - err = translate_error(res); + ret = translate_error(res); } while (false); - return err; + return ret; } static msg_t drv_open_file(void *instance, const char *path, int flags, vfs_file_node_c **vfnpp) { - msg_t err; + msg_t ret; do { vfs_fatfs_driver_c *drvp = (vfs_fatfs_driver_c *)instance; @@ -400,14 +442,14 @@ static msg_t drv_open_file(void *instance, mode = translate_oflag(flags); if (mode == (BYTE)0) { - err = CH_RET_EINVAL; + ret = CH_RET_EINVAL; break; } fffnp = chPoolAlloc(&vfs_fatfs_driver_static.file_nodes_pool); if (fffnp != NULL) { - res = f_open(&fffnp->file, (TCHAR *)path, mode); + res = f_open(&fffnp->file, (const TCHAR *)path, mode); if (res == FR_OK) { /* Node object initialization.*/ @@ -417,32 +459,37 @@ static msg_t drv_open_file(void *instance, fffnp->stream.vmt = &file_stream_vmt; *vfnpp = (vfs_file_node_c *)fffnp; - err = CH_RET_SUCCESS; + ret = CH_RET_SUCCESS; break; } chPoolFree(&vfs_fatfs_driver_static.file_nodes_pool, (void *)fffnp); } + else { + ret = CH_RET_ENOMEM; + break; + } - err = translate_error(res); + ret = translate_error(res); } while (false); - return err; + return ret; } msg_t drv_unlink(void *instance, const char *path) { (void)instance; - return translate_error(f_unlink(path)); + return translate_error(f_unlink((const TCHAR *)path)); } msg_t drv_rename(void *instance, const char *oldpath, const char *newpath) { (void)instance; - return translate_error(f_rename(oldpath, newpath)); + return translate_error(f_rename((const TCHAR *)oldpath, + (const TCHAR *)newpath)); } msg_t drv_mkdir(void *instance, const char *path, vfs_mode_t mode) { @@ -450,14 +497,14 @@ msg_t drv_mkdir(void *instance, const char *path, vfs_mode_t mode) { (void)instance; (void)mode; /* Not handled by FatFS.*/ - return translate_error(f_mkdir(path)); + return translate_error(f_mkdir((const TCHAR *)path)); } msg_t drv_rmdir(void *instance, const char *path) { (void)instance; - return translate_error(f_rmdir(path)); + return translate_error(f_rmdir((const TCHAR *)path)); } static void *node_dir_addref(void *instance) { @@ -486,22 +533,22 @@ static msg_t node_dir_stat(void *instance, vfs_stat_t *sp) { static msg_t node_dir_first(void *instance, vfs_direntry_info_t *dip) { vfs_fatfs_dir_node_c *ffdnp = (vfs_fatfs_dir_node_c *)instance; - msg_t err; + msg_t ret; FRESULT res; res = f_rewinddir(&ffdnp->dir); if (res == FR_OK) { - err = node_dir_next(instance, dip); + ret = node_dir_next(instance, dip); } else { - err = translate_error(res); + ret = translate_error(res); } - return err; + return ret; } static msg_t node_dir_next(void *instance, vfs_direntry_info_t *dip) { - msg_t err; + msg_t ret; do { vfs_fatfs_dir_node_c *ffdnp = (vfs_fatfs_dir_node_c *)instance; @@ -514,26 +561,30 @@ static msg_t node_dir_next(void *instance, vfs_direntry_info_t *dip) { res = f_readdir(&ffdnp->dir, fip); if (res == FR_OK) { if (fip->fname[0] == '\0') { - err = (msg_t)0; + ret = (msg_t)0; } else { dip->mode = translate_mode(fip->fattrib); dip->size = (vfs_offset_t)fip->fsize; strncpy(dip->name, fip->fname, VFS_CFG_NAMELEN_MAX); dip->name[VFS_CFG_NAMELEN_MAX] = '\0'; - err = (msg_t)1; + ret = (msg_t)1; } } else { - err = translate_error(res); + ret = translate_error(res); } chPoolFree(&vfs_fatfs_driver_static.info_nodes_pool, (void *)fip); } + else { + ret = CH_RET_ENOMEM; + break; + } } while (false); - return err; + return ret; } static void *node_file_addref(void *instance) { diff --git a/os/vfs/drivers/overlay/drvoverlay.c b/os/vfs/drivers/overlay/drvoverlay.c index c8b248368..05c695771 100644 --- a/os/vfs/drivers/overlay/drvoverlay.c +++ b/os/vfs/drivers/overlay/drvoverlay.c @@ -47,6 +47,7 @@ static msg_t drv_set_cwd(void *instance, const char *path); static msg_t drv_get_cwd(void *instance, char *buf, size_t size); +static msg_t drv_stat(void *instance, const char *path, vfs_stat_t *sp); static msg_t drv_open_dir(void *instance, const char *path, vfs_directory_node_c **vdnpp); static msg_t drv_open_file(void *instance, const char *path, @@ -59,6 +60,7 @@ static msg_t drv_rmdir(void *instance, const char *path); static const struct vfs_overlay_driver_vmt driver_vmt = { .set_cwd = drv_set_cwd, .get_cwd = drv_get_cwd, + .stat = drv_stat, .open_dir = drv_open_dir, .open_file = drv_open_file, .unlink = drv_unlink, @@ -213,6 +215,10 @@ static msg_t open_absolute_dir(vfs_overlay_driver_c *drvp, ret = CH_RET_SUCCESS; break; } + else { + ret = CH_RET_ENOMEM; + break; + } } else { /* Not the root.*/ vfs_driver_c *dp; @@ -374,6 +380,65 @@ static msg_t drv_get_cwd(void *instance, char *buf, size_t size) { return CH_RET_SUCCESS; } +static msg_t drv_stat(void *instance, const char *path, vfs_stat_t *sp) { + msg_t ret; + char *buf; + + /* Taking a path buffer from the pool.*/ + buf = vfs_buffer_take(); + + do { + vfs_overlay_driver_c *drvp = (vfs_overlay_driver_c *)instance; + const char *scanpath; + + /* Building the absolute path based on current directory.*/ + ret = build_absolute_path(drvp, buf, path); + CH_BREAK_ON_ERROR(ret); + + /* Skipping the root separator.*/ + scanpath = buf + 1; + + /* If it is not root checking among mounted drivers.*/ + if (*scanpath != '\0') { + vfs_driver_c *dp; + + /* Searching for a match among registered overlays.*/ + ret = match_driver(drvp, &scanpath, &dp); + if (!CH_RET_IS_ERROR(ret)) { + /* Delegating directory creation to a registered driver.*/ + ret = dp->vmt->stat((void *)dp, scanpath, sp); + } + break; + } + + /* Is there an overlaid driver? if so we need to pass request + processing there.*/ + if (drvp->overlaid_drv != NULL) { + + /* Processing the prefix, if defined.*/ + if (drvp->path_prefix != NULL) { + if (path_prepend(buf, + drvp->path_prefix, + VFS_CFG_PATHLEN_MAX + 1) == (size_t)0) { + ret = CH_RET_ENAMETOOLONG; + break; + } + } + + /* Passing the combined path to the overlaid driver.*/ + ret = drvp->overlaid_drv->vmt->stat((void *)drvp->overlaid_drv, buf, sp); + } + else { + ret = CH_RET_ENOENT; + } + } while (false); + + /* Buffer returned.*/ + vfs_buffer_release(buf); + + return ret; +} + static msg_t drv_open_dir(void *instance, const char *path, vfs_directory_node_c **vdnpp) { diff --git a/os/vfs/include/vfs.h b/os/vfs/include/vfs.h index ecdf3f064..dcb22a19a 100644 --- a/os/vfs/include/vfs.h +++ b/os/vfs/include/vfs.h @@ -131,6 +131,7 @@ extern "C" { void vfsInit(void); msg_t vfsChangeCurrentDirectory(const char *path); msg_t vfsGetCurrentDirectory(char *buf, size_t size); + msg_t vfsStat(const char *path, vfs_stat_t *sp); msg_t vfsOpen(const char *path, int flags, vfs_node_c **vnpp); msg_t vfsOpenDirectory(const char *name, vfs_directory_node_c **vdnpp); msg_t vfsOpenFile(const char *name, int flags, vfs_file_node_c **vfnpp); diff --git a/os/vfs/include/vfsdrivers.h b/os/vfs/include/vfsdrivers.h index 7b6d73000..acc4a26fa 100644 --- a/os/vfs/include/vfsdrivers.h +++ b/os/vfs/include/vfsdrivers.h @@ -69,6 +69,9 @@ __base_object_methods \ msg_t (*set_cwd)(void *instance, const char *path); \ msg_t (*get_cwd)(void *instance, char *buf, size_t size); \ + msg_t (*stat)(void *instance, \ + const char *path, \ + vfs_stat_t *sp); \ msg_t (*open_dir)(void *instance, \ const char *path, \ vfs_directory_node_c **vdnpp); \ @@ -120,6 +123,7 @@ extern "C" { const char *path, int flags, vfs_node_c **vnpp); + msg_t drv_stat_unimpl(void *instance, vfs_stat_t *sp); msg_t drv_unlink_unimpl(void *instance, const char *path); msg_t drv_rename_unimpl(void *instance, const char *oldpath, @@ -167,6 +171,23 @@ static inline msg_t vfsDrvGetCurrentDirectory(vfs_driver_c *drvp, return drvp->vmt->get_cwd(drvp, buf, size); } +/** + * @brief Returns file or directory information. + *. + * @param[in] drvp Pointer to the @p vfs_driver_c object. + * @param[in] path Absolute path of the node to be examined. + * @param[out] sp Pointer to a @p vfs_stat_t structure. + * @return The operation result. + * + * @api + */ +static inline msg_t vfsDrvStat(vfs_driver_c *drvp, + const char *path, + vfs_stat_t *sp) { + + return drvp->vmt->stat(drvp, path, sp); +} + /** * @brief Opens a VFS directory. * diff --git a/os/vfs/src/vfs.c b/os/vfs/src/vfs.c index 20961ce7e..9df25403f 100644 --- a/os/vfs/src/vfs.c +++ b/os/vfs/src/vfs.c @@ -101,6 +101,20 @@ msg_t vfsGetCurrentDirectory(char *buf, size_t size) { return vfsDrvGetCurrentDirectory(vfs_root, buf, size); } +/** + * @brief Returns file or directory information. + *. + * @param[in] path Absolute path of the node to be examined. + * @param[out] sp Pointer to a @p vfs_stat_t structure. + * @return The operation result. + * + * @api + */ +msg_t vfsStat(const char *path, vfs_stat_t *sp) { + + return vfsDrvStat(vfs_root, path, sp); +} + /** * @brief Opens a VFS file or directory. * diff --git a/os/vfs/src/vfsdrivers.c b/os/vfs/src/vfsdrivers.c index eb2e9f3d7..70ae2849e 100644 --- a/os/vfs/src/vfsdrivers.c +++ b/os/vfs/src/vfsdrivers.c @@ -83,6 +83,14 @@ msg_t vfsDrvOpen(vfs_driver_c *drvp, return ret; } +msg_t drv_stat_unimpl(void *instance, vfs_stat_t *sp) { + + (void)instance; + (void)sp; + + return CH_RET_ENOSYS; +} + msg_t drv_unlink_unimpl(void *instance, const char *path) { (void)instance;