// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include #include #include #include #include #include #include struct __dirstream { purefs::fs::filesystem::fsdir dirh; size_t position; struct dirent dir_data; }; namespace { template auto invoke_fs(int &error, T Base::*lfs_fun, Args &&... args) -> decltype((static_cast(nullptr)->*lfs_fun)(std::forward(args)...)) { auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { error = EIO; return -1; } auto ret = (vfs.get()->*lfs_fun)(std::forward(args)...); if (ret < 0) { error = -ret; ret = -1; } return ret; } } // namespace namespace vfsn::internal::syscalls { int open(int &_errno_, const char *file, int flags, int mode) { return invoke_fs(_errno_, &purefs::fs::filesystem::open, file, flags, mode); } long close(int &_errno_, int fd) { return invoke_fs(_errno_, &purefs::fs::filesystem::close, fd); } long write(int &_errno_, int fd, const void *buf, size_t cnt) { return invoke_fs(_errno_, &purefs::fs::filesystem::write, fd, reinterpret_cast(buf), cnt); } long read(int &_errno_, int fd, void *buf, size_t cnt) { return invoke_fs(_errno_, &purefs::fs::filesystem::read, fd, reinterpret_cast(buf), cnt); } off_t lseek(int &_errno_, int fd, off_t pos, int dir) { return invoke_fs(_errno_, &purefs::fs::filesystem::seek, fd, pos, dir); } int fstat(int &_errno_, int fd, struct stat *pstat) { if (pstat) { return invoke_fs(_errno_, &purefs::fs::filesystem::fstat, fd, *pstat); } else { _errno_ = EINVAL; return -1; } } int link(int &_errno_, const char *existing, const char *newLink) { return invoke_fs(_errno_, &purefs::fs::filesystem::link, existing, newLink); } int unlink(int &_errno_, const char *name) { return invoke_fs(_errno_, &purefs::fs::filesystem::unlink, name); } int fcntl(int &_errno_, int fd, int cmd, int arg) { _errno_ = ENOTSUP; return -1; } int stat(int &_errno_, const char *file, struct stat *pstat) { if (pstat) { return invoke_fs(_errno_, &purefs::fs::filesystem::stat, file, *pstat); } else { _errno_ = EINVAL; return -1; } } int chdir(int &_errno_, const char *path) { return invoke_fs(_errno_, &purefs::fs::filesystem::chdir, path); } char *getcwd(int &_errno_, char *buf, size_t size) { if (!buf) { _errno_ = EINVAL; return nullptr; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return nullptr; } const auto ret = vfs->getcwd(); const auto slen = ret.copy(buf, size); if (size < slen) { buf[slen] = '\0'; } return buf; } int rename(int &_errno_, const char *oldName, const char *newName) { return invoke_fs(_errno_, &purefs::fs::filesystem::rename, oldName, newName); } int mkdir(int &_errno_, const char *path, uint32_t mode) { return invoke_fs(_errno_, &purefs::fs::filesystem::mkdir, path, mode); } DIR *opendir(int &_errno_, const char *dirname) { __dirstream *ret{}; if (!dirname) { _errno_ = EIO; return ret; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return ret; } ret = new (std::nothrow) __dirstream; if (!ret) { _errno_ = ENOMEM; return ret; } ret->position = 0; ret->dirh = vfs->diropen(dirname); if (!ret->dirh) { delete ret; _errno_ = EIO; ret = nullptr; } else if (ret->dirh->error()) { _errno_ = -ret->dirh->error(); delete ret; ret = nullptr; } return ret; } int closedir(int &_errno_, DIR *dirp) { if (!dirp) { _errno_ = EBADF; return -1; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return -1; } auto ret = vfs->dirclose(dirp->dirh); if (ret < 0) { _errno_ = -ret; ret = -1; } delete dirp; return ret; } struct dirent *readdir(int &_errno_, DIR *dirp) { if (!dirp) { _errno_ = EBADF; return nullptr; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return nullptr; } std::string fname; struct stat stdata; auto ret = vfs->dirnext(dirp->dirh, fname, stdata); if (ret < 0) { if (ret != -ENODATA) { _errno_ = -ret; } return nullptr; } else { if (fname.size() >= sizeof(dirp->dir_data.d_name)) { _errno_ = EOVERFLOW; return nullptr; } dirp->position += 1; dirp->dir_data.d_ino = stdata.st_ino; dirp->dir_data.d_type = S_ISREG(stdata.st_mode) ? DT_REG : DT_DIR; dirp->dir_data.d_reclen = fname.size(); std::strncpy(dirp->dir_data.d_name, fname.c_str(), sizeof(dirp->dir_data.d_name)); return &dirp->dir_data; } } int readdir_r(int &_errno_, DIR *dirp, struct dirent *entry, struct dirent **result) { if (!dirp) { _errno_ = EBADF; return -1; } if (!*result) { _errno_ = EINVAL; return -1; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return -1; } std::string fname; struct stat stdata; auto ret = vfs->dirnext(dirp->dirh, fname, stdata); if (ret == -ENODATA) { *result = nullptr; return 0; } else if (ret < 0) { _errno_ = -ret; return -1; } else { if (fname.size() >= sizeof(dirp->dir_data.d_name)) { _errno_ = EOVERFLOW; return -1; } dirp->position += 1; entry->d_ino = stdata.st_ino; entry->d_type = S_ISREG(stdata.st_mode) ? DT_REG : DT_DIR; entry->d_reclen = fname.size(); std::strncpy(entry->d_name, fname.c_str(), sizeof(entry->d_name)); *result = entry; return 0; } } void rewinddir(int &_errno_, DIR *dirp) { if (!dirp) { _errno_ = EBADF; return; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return; } auto res = vfs->dirreset(dirp->dirh); if (res < 0) { _errno_ = -res; return; } dirp->position = 0; } void seekdir(int &_errno_, DIR *dirp, long int loc) { if (!dirp) { _errno_ = EBADF; return; } if (loc < 0) { _errno_ = EINVAL; return; } auto vfs = purefs::subsystem::vfs_core(); if (!vfs) { _errno_ = EIO; return; } if (long(dirp->position) > loc) { vfs->dirreset(dirp->dirh); dirp->position = 0; } std::string name; struct stat st; while ((long(dirp->position) < loc) && (vfs->dirnext(dirp->dirh, name, st)) >= 0) { dirp->position += 1; } } long int telldir(int &_errno_, DIR *dirp) { if (!dirp) { _errno_ = EBADF; return -1; } return dirp->position; } int chmod(int &_errno_, const char *path, mode_t mode) { return invoke_fs(_errno_, &purefs::fs::filesystem::chmod, path, mode); } int fchmod(int &_errno_, int fd, mode_t mode) { return invoke_fs(_errno_, &purefs::fs::filesystem::fchmod, fd, mode); } int fsync(int &_errno_, int fd) { return invoke_fs(_errno_, &purefs::fs::filesystem::fsync, fd); } int statvfs(int &_errno_, const char *path, struct statvfs *buf) { if (!buf) { _errno_ = EINVAL; return -1; } else { return invoke_fs(_errno_, &purefs::fs::filesystem::stat_vfs, path, *buf); } } } // namespace vfsn::internal::syscalls