/*---------------------------------------------------------------------------- * 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; }