
1. elfloader for shared object example: TencentOS-tiny\examples\elfloader_shared_object keil: TencentOS-tiny\board\TencentOS_tiny_EVB_MX_Plus\KEIL\elfloader_shared_object 2. elfloader for relocatable object: example: TencentOS-tiny\examples\elfloader_relocatable_object keil: TencentOS-tiny\board\TencentOS_tiny_EVB_MX_Plus\KEIL\elfloader_relocatable_object 3. TODO: - add icache/dcache flush when module is loaded - support more relocation type in elfloader_arch_relocate
695 lines
15 KiB
C
695 lines
15 KiB
C
/*----------------------------------------------------------------------------
|
|
* Tencent is pleased to support the open source community by making TencentOS
|
|
* available.
|
|
*
|
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
|
* If you have downloaded a copy of the TencentOS binary from Tencent, please
|
|
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
|
|
*
|
|
* If you have downloaded a copy of the TencentOS source code from Tencent,
|
|
* please note that TencentOS source code is licensed under the BSD 3-Clause
|
|
* License, except for the third-party components listed below which are
|
|
* subject to different license terms. Your integration of TencentOS into your
|
|
* own projects may require compliance with the BSD 3-Clause License, as well
|
|
* as the other licenses applicable to the third-party components included
|
|
* within TencentOS.
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include "tos_vfs.h"
|
|
|
|
__API__ int tos_vfs_open(const char *pathname, vfs_oflag_t flags)
|
|
{
|
|
int path_len = 0, ret = -1;
|
|
char *relative_path = K_NULL;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(pathname);
|
|
|
|
path_len = strlen(pathname);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
if (pathname[path_len - 1] == '/') {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
inode = vfs_inode_find(pathname, (const char **)&relative_path);
|
|
if (!inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
file = vfs_file_alloc();
|
|
if (!file) {
|
|
ret = -VFS_ERR_FILE_NO_AVAILABLE;
|
|
goto errout0;
|
|
}
|
|
|
|
file->flags = flags;
|
|
file->pos = 0;
|
|
file->inode = inode;
|
|
file->private = K_NULL;
|
|
|
|
if (VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
if (!relative_path) {
|
|
ret = -VFS_ERR_PARA_INVALID;
|
|
goto errout1;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->open) {
|
|
ret = inode->ops.fs_ops->open(file, relative_path, flags);
|
|
}
|
|
} else if (VFS_INODE_IS_CHAR_DEVICE(inode)) {
|
|
if (inode->ops.cd_ops->open) {
|
|
ret = inode->ops.cd_ops->open(file);
|
|
}
|
|
} else {
|
|
goto errout1;
|
|
}
|
|
|
|
if (ret < 0) {
|
|
goto errout1;
|
|
}
|
|
|
|
vfs_inode_refinc(inode);
|
|
|
|
return vfs_file2fd(file);
|
|
|
|
errout1:
|
|
vfs_file_free(file);
|
|
|
|
errout0:
|
|
vfs_inode_release(inode);
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_close(int fd)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
|
|
if (VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
if (inode->ops.fs_ops->close) {
|
|
ret = inode->ops.fs_ops->close(file);
|
|
}
|
|
} else if (VFS_INODE_IS_CHAR_DEVICE(inode)) {
|
|
if (inode->ops.cd_ops->close) {
|
|
ret = inode->ops.cd_ops->close(file);
|
|
}
|
|
} else {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (ret == 0) {
|
|
vfs_inode_release(inode);
|
|
vfs_file_free(file);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ ssize_t tos_vfs_read(int fd, void *buf, size_t count)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
if (!buf) {
|
|
return -VFS_ERR_BUFFER_NULL;
|
|
}
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
|
|
if (VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
if (inode->ops.fs_ops->read) {
|
|
ret = inode->ops.fs_ops->read(file, buf, count);
|
|
}
|
|
} else if (VFS_INODE_IS_CHAR_DEVICE(inode)) {
|
|
if (inode->ops.cd_ops->read) {
|
|
ret = inode->ops.cd_ops->read(file, buf, count);
|
|
}
|
|
} else {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ ssize_t tos_vfs_write(int fd, const void *buf, size_t count)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
if (!buf) {
|
|
return -VFS_ERR_BUFFER_NULL;
|
|
}
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
|
|
if (VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
if (inode->ops.fs_ops->write) {
|
|
ret = inode->ops.fs_ops->write(file, buf, count);
|
|
}
|
|
} else if (VFS_INODE_IS_CHAR_DEVICE(inode)) {
|
|
if (inode->ops.cd_ops->write) {
|
|
ret = inode->ops.cd_ops->write(file, buf, count);
|
|
}
|
|
} else {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ vfs_off_t tos_vfs_lseek(int fd, vfs_off_t offset, vfs_whence_t whence)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
|
|
if (VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
if (inode->ops.fs_ops->lseek) {
|
|
ret = inode->ops.fs_ops->lseek(file, offset, whence);
|
|
}
|
|
} else if (VFS_INODE_IS_CHAR_DEVICE(inode)) {
|
|
if (inode->ops.cd_ops->lseek) {
|
|
ret = inode->ops.cd_ops->lseek(file, offset, whence);
|
|
}
|
|
} else {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_ioctl(int fd, unsigned long request, ...)
|
|
{
|
|
int ret = -1;
|
|
va_list ap;
|
|
unsigned long arg;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
va_start(ap, request);
|
|
arg = va_arg(ap, unsigned long);
|
|
va_end(ap);
|
|
|
|
inode = file->inode;
|
|
|
|
if (VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
if (inode->ops.fs_ops->ioctl) {
|
|
ret = inode->ops.fs_ops->ioctl(file, request, arg);
|
|
}
|
|
} else if (VFS_INODE_IS_CHAR_DEVICE(inode)) {
|
|
if (inode->ops.cd_ops->ioctl) {
|
|
ret = inode->ops.cd_ops->ioctl(file, request, arg);
|
|
}
|
|
} else {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_sync(int fd)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->sync) {
|
|
ret = inode->ops.fs_ops->sync(file);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_dup(int oldfd)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *old_file = K_NULL, *new_file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
old_file = vfs_fd2file(oldfd);
|
|
if (!old_file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = old_file->inode;
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
new_file = vfs_file_dup(old_file);
|
|
if (!new_file) {
|
|
return -VFS_ERR_FILE_NO_AVAILABLE;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->dup) {
|
|
ret = inode->ops.fs_ops->dup(old_file, new_file);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
vfs_file_free(new_file);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_fstat(int fd, vfs_fstat_t *buf)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
if (!buf) {
|
|
return -VFS_ERR_BUFFER_NULL;
|
|
}
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->fstat) {
|
|
ret = inode->ops.fs_ops->fstat(file, buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_ftruncate(int fd, vfs_off_t length)
|
|
{
|
|
int ret = -1;
|
|
vfs_file_t *file = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
file = vfs_fd2file(fd);
|
|
if (!file) {
|
|
return -VFS_ERR_FILE_NOT_OPEN;
|
|
}
|
|
|
|
inode = file->inode;
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->truncate) {
|
|
ret = inode->ops.fs_ops->truncate(file, length);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ VFS_DIR *tos_vfs_opendir(const char *name)
|
|
{
|
|
int path_len = 0, ret = -1;
|
|
char *relative_path = K_NULL;
|
|
vfs_dir_t *dir = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
if (!name) {
|
|
return K_NULL;
|
|
}
|
|
|
|
path_len = strlen(name);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return K_NULL;
|
|
}
|
|
|
|
inode = vfs_inode_find(name, (const char **)&relative_path);
|
|
if (!inode) {
|
|
return K_NULL;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return K_NULL;
|
|
}
|
|
|
|
dir = vfs_dir_alloc();
|
|
if (!dir) {
|
|
return K_NULL;
|
|
}
|
|
|
|
dir->pos = 0;
|
|
dir->inode = inode;
|
|
dir->private = K_NULL;
|
|
|
|
if (inode->ops.fs_ops->opendir) {
|
|
ret = inode->ops.fs_ops->opendir(dir, relative_path);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
vfs_dir_free(dir);
|
|
vfs_inode_release(inode);
|
|
}
|
|
|
|
vfs_inode_refinc(inode);
|
|
|
|
return (VFS_DIR *)dir;
|
|
}
|
|
|
|
__API__ int tos_vfs_closedir(VFS_DIR *dirp)
|
|
{
|
|
int ret = -1;
|
|
vfs_dir_t *dir = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(dirp);
|
|
|
|
dir = (vfs_dir_t *)dirp;
|
|
inode = dir->inode;
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->closedir) {
|
|
ret = inode->ops.fs_ops->closedir(dir);
|
|
}
|
|
|
|
if (ret == 0) {
|
|
vfs_inode_release(inode);
|
|
vfs_dir_free(dir);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ vfs_dirent_t *tos_vfs_readdir(VFS_DIR *dirp)
|
|
{
|
|
int ret = -1;
|
|
vfs_dir_t *dir = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
if (!dir) {
|
|
return K_NULL;
|
|
}
|
|
|
|
dir = (vfs_dir_t *)dirp;
|
|
inode = dir->inode;
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return K_NULL;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->readdir) {
|
|
ret = inode->ops.fs_ops->readdir(dir, &dir->dirent);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
return K_NULL;
|
|
}
|
|
|
|
return &dir->dirent;
|
|
}
|
|
|
|
__API__ int tos_vfs_rewinddir(VFS_DIR *dirp)
|
|
{
|
|
int ret = -1;
|
|
vfs_dir_t *dir = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(dir);
|
|
|
|
dir = (vfs_dir_t *)dirp;
|
|
inode = dir->inode;
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->rewinddir) {
|
|
ret = inode->ops.fs_ops->rewinddir(dir);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_statfs(const char *path, vfs_fsstat_t *buf)
|
|
{
|
|
int ret = -1;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(path);
|
|
if (!buf) {
|
|
return -VFS_ERR_BUFFER_NULL;
|
|
}
|
|
|
|
inode = vfs_inode_find(path, K_NULL);
|
|
if (!inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->statfs) {
|
|
ret = inode->ops.fs_ops->statfs(inode, buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_unlink(const char *pathname)
|
|
{
|
|
int path_len, ret = -1;
|
|
char *relative_path = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(pathname);
|
|
|
|
path_len = strlen(pathname);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
if (pathname[path_len - 1] == '/') {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
inode = vfs_inode_find(pathname, (const char **)&relative_path);
|
|
if (!inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (!relative_path) {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->unlink) {
|
|
ret = inode->ops.fs_ops->unlink(inode, relative_path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_mkdir(const char *pathname)
|
|
{
|
|
int path_len, ret = -1;
|
|
char *relative_path = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(pathname);
|
|
|
|
path_len = strlen(pathname);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
inode = vfs_inode_find(pathname, (const char **)&relative_path);
|
|
if (!inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (!relative_path) {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->mkdir) {
|
|
ret = inode->ops.fs_ops->mkdir(inode, relative_path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_rmdir(const char *pathname)
|
|
{
|
|
int path_len, ret = -1;
|
|
char *relative_path = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(pathname);
|
|
|
|
path_len = strlen(pathname);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
inode = vfs_inode_find(pathname, (const char **)&relative_path);
|
|
if (!inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (!relative_path) {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->rmdir) {
|
|
ret = inode->ops.fs_ops->rmdir(inode, relative_path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_rename(const char *oldpath, const char *newpath)
|
|
{
|
|
int path_len, ret = -1;
|
|
char *old_relative_path = K_NULL;
|
|
char *new_relative_path = K_NULL;
|
|
vfs_inode_t *old_inode = K_NULL, *new_inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(oldpath);
|
|
TOS_PTR_SANITY_CHECK(newpath);
|
|
|
|
path_len = strlen(oldpath);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
path_len = strlen(newpath);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
old_inode = vfs_inode_find(oldpath, (const char **)&old_relative_path);
|
|
if (!old_inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
new_inode = vfs_inode_find(newpath, (const char **)&new_relative_path);
|
|
if (!new_inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(old_inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (old_inode != new_inode) {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
if (!old_relative_path || !new_relative_path) {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
if (old_inode->ops.fs_ops->rename) {
|
|
ret = old_inode->ops.fs_ops->rename(old_inode, old_relative_path, new_relative_path);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
__API__ int tos_vfs_stat(const char *pathname, vfs_fstat_t *buf)
|
|
{
|
|
int path_len, ret = -1;
|
|
char *relative_path = K_NULL;
|
|
vfs_inode_t *inode = K_NULL;
|
|
|
|
TOS_PTR_SANITY_CHECK(pathname);
|
|
if (!buf) {
|
|
return -VFS_ERR_BUFFER_NULL;
|
|
}
|
|
|
|
path_len = strlen(pathname);
|
|
if (path_len > TOS_CFG_VFS_PATH_MAX) {
|
|
return -VFS_ERR_PATH_TOO_LONG;
|
|
}
|
|
|
|
if (pathname[path_len - 1] == '/') {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
inode = vfs_inode_find(pathname, (const char **)&relative_path);
|
|
if (!inode) {
|
|
return -VFS_ERR_INODE_NOT_FOUND;
|
|
}
|
|
|
|
if (!VFS_INODE_IS_FILESYSTEM(inode)) {
|
|
return -VFS_ERR_INODE_INVALID;
|
|
}
|
|
|
|
if (!relative_path) {
|
|
return -VFS_ERR_PARA_INVALID;
|
|
}
|
|
|
|
if (inode->ops.fs_ops->stat) {
|
|
ret = inode->ops.fs_ops->stat(inode, relative_path, buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|