xiuos/Ubiquitous/XiZi/fs/shared/src/iot-vfs.c

1188 lines
26 KiB
C

/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <xizi.h>
#include <iot-vfs.h>
#include <iot-vfs_posix.h>
DoubleLinklistType mnt_list;
static int mnt_list_lock;
char working_dir[MAX_PATH + 1];
static int working_dir_lock;
static struct Filesystem *fstable[FSTYPE_END];
static struct FileDescriptor *fdtable[FD_MAX - FD_OFFSET];
static int fdtable_lock;
static struct MountPoint *GetMountPoint(const char *path)
{
struct MountPoint *mp = NULL, *itr;
size_t longest_match = 0;
size_t len, name_len = strlen(path);
struct SysDoubleLinklistNode *node;
KMutexObtain(mnt_list_lock, WAITING_FOREVER);
DOUBLE_LINKLIST_FOR_EACH(node, &mnt_list) {
itr =CONTAINER_OF(node, struct MountPoint, node);
len = itr->mnt_point_len;
if ((len < longest_match) || (len > name_len)) {
continue;
}
if ((len > 1) && (path[len] != '/') && (path[len] != '\0')) {
continue;
}
if (strncmp(path, itr->mnt_point, len) == 0) {
mp = itr;
longest_match = len;
}
}
KMutexAbandon(mnt_list_lock);
return mp;
}
char *GetAbsolutePath(const char *path)
{
char *abspath, *tmp;
char *prev, *curr;
int len;
NULL_PARAM_CHECK(path);
if (path[0] == '/') {
len = strlen(path) + 1;
tmp = (char *)malloc(len);
if (tmp == NULL)
return NULL;
strcpy(tmp, path);
} else {
len = strlen(working_dir) + strlen(path) + 2;
tmp = (char *)malloc(len);
if (tmp == NULL)
return NULL;
strcpy(tmp, working_dir);
strcat(tmp, "/");
strcat(tmp, path);
}
abspath = (char *)malloc(len);
if (abspath == NULL) {
free(tmp);
return NULL;
}
memset(abspath, 0, len);
for (curr = tmp; curr < tmp + len; curr++)
if (*curr == '/')
*curr = '\0';
curr = tmp;
while (curr < tmp + len) {
if (*curr == '\0') {
curr++;
continue;
}
if (*curr == '.') {
if (strlen(curr) == 1) {
*curr = '\0';
curr++;
} else if (strlen(curr) == 2 && *(curr + 1) == '.') {
prev = curr - 1;
while (prev >= tmp && *prev == '\0')
prev--;
if (prev >= tmp) {
while (prev > tmp && *(prev - 1) != '\0')
prev--;
memset(prev, 0, strlen(prev));
}
*curr = *(curr + 1) = '\0';
curr += 2;
}
} else {
curr += strlen(curr);
}
}
curr = tmp;
while (curr < tmp + len) {
if (*curr == '\0') {
curr++;
} else {
strcat(abspath, "/");
strcat(abspath, curr);
curr += strlen(curr);
}
}
if (abspath[0] == '\0') {
abspath[0] = '/';
abspath[1] = '\0';
}
free(tmp);
return abspath;
}
static char *GetRelativePath(const char *prefix, const char *abspath)
{
char *relpath;
int prefix_len, abspath_len;
prefix_len = strlen(prefix);
abspath_len = strlen(abspath);
if (prefix_len == abspath_len)
return "";
relpath = (char *)abspath + prefix_len;
while (*relpath == '/')
relpath++;
return relpath;
}
int NewFileDescriptor(struct FileDescriptor **fdptr)
{
int fd;
struct FileDescriptor *fdp;
KMutexObtain(fdtable_lock, WAITING_FOREVER);
if (fdptr)
*fdptr = NULL;
for (fd = 0; fd < FD_MAX - FD_OFFSET; fd++)
if (fdtable[fd] == NULL)
break;
if (fd >= FD_MAX - FD_OFFSET) {
fd = -1;
goto err;
}
fdp = malloc(sizeof(struct FileDescriptor));
if (fdp == NULL) {
fd = -1;
goto err;
}
fdtable[fd] = fdp;
fd += FD_OFFSET;
if (fdptr)
*fdptr = fdp;
err:
KMutexAbandon(fdtable_lock);
return fd;
}
struct FileDescriptor *GetFileDescriptor(int fd)
{
if (fd < 0 || fd >= FD_MAX)
return NULL;
#if defined(FS_VFS_DEVFS) && defined(LIB_POSIX)
extern int LibcStdioGetConsole();
if (fd <= 2)
fd = LibcStdioGetConsole();
#endif
fd -= FD_OFFSET;
if (fd < 0)
return NULL;
return fdtable[fd];
}
void FreeFileDescriptor(struct FileDescriptor *fdp)
{
KMutexObtain(fdtable_lock, WAITING_FOREVER);
for (int i = 0; i < FD_MAX - FD_OFFSET; i++)
if (fdtable[i] == fdp) {
free(fdp->path);
free(fdp);
fdtable[i] = NULL;
break;
}
KMutexAbandon(fdtable_lock);
}
int MountFilesystem(const char *bus_name,
const char *dev_name, const char *drv_name,
enum FilesystemType fs_type, const char *path)
{
struct MountPoint *mp = NULL, *itr;
struct Bus *bus;
HardwareDevType dev;
DriverType drv;
struct SysDoubleLinklistNode *node;
int ret = -EINVAL;
if (bus_name != NULL && dev_name != NULL && drv_name != NULL) {
bus = BusFind(bus_name);
if (bus == NULL) {
SYS_ERR("%s: bus %s not found\n", __func__, bus_name);
return -ENXIO;
}
dev = BusFindDevice(bus, dev_name);
if (dev == NULL) {
SYS_ERR("%s: dev %s on bus %s not found\n", __func__, dev_name, bus_name);
return -ENXIO;
}
bus->owner_haldev = dev;
drv = BusFindDriver(bus, drv_name);
if (drv == NULL) {
SYS_ERR("%s: drv %s on bus %s not found\n", __func__, drv_name, bus_name);
return -ENXIO;
}
bus->owner_driver = drv;
} else {
dev = NULL;
}
if (fs_type >= FSTYPE_END) {
SYS_ERR("%s: invalid filesystem\n", __func__);
return -EINVAL;
}
if (fstable[fs_type] == NULL) {
SYS_ERR("%s: specified filesystem not registered\n", __func__);
return -EINVAL;
}
if (path == NULL || path[0] != '/') {
SYS_ERR("%s: invalid mount point\n", __func__);
return -EINVAL;
}
mp = malloc(sizeof(struct MountPoint));
if (mp == NULL) {
SYS_ERR("%s: memory not enough\n", __func__);
return -ENOMEM;
}
KMutexObtain(mnt_list_lock, WAITING_FOREVER);
mp->fs_type = fs_type;
mp->fs = fstable[fs_type];
mp->bus = bus;
mp->dev = dev;
mp->drv = drv;
mp->fs_data = NULL;
mp->mnt_point_len = strlen(path);
mp->mnt_point = strdup(path);
if (mp->mnt_point == NULL) {
SYS_ERR("%s: memory not enough\n", __func__);
ret = -ENOMEM;
goto err;
}
if (mp->fs->mount == NULL) {
SYS_ERR("%s: specified filesystem does not have mount function\n",
__func__);
ret = -EINVAL;
goto err;
}
DOUBLE_LINKLIST_FOR_EACH(node, &mnt_list) {
itr =CONTAINER_OF(node, struct MountPoint, node);
if (mp->mnt_point_len != itr->mnt_point_len)
continue;
if (strncmp(mp->mnt_point, itr->mnt_point,
mp->mnt_point_len) == 0) {
SYS_ERR("%s: mount point already exists\n", __func__);
ret = -EINVAL;
goto err;
}
}
if (dev != NULL)
if (BusDevOpen(dev) != 0) {
SYS_ERR("%s: failed to open device %s on bus %s\n",
__func__, dev_name, bus_name);
ret = -EINVAL;
goto err;
}
ret = mp->fs->mount(mp);
if (ret < 0) {
SYS_ERR("%s: filesystem mount failed\n", __func__);
if (dev)
BusDevClose(dev);
goto err;
}
DoubleLinkListInsertNodeBefore(&mnt_list, &mp->node);
DBG("%s: filesystem mounted at %s\n", __func__, path);
err:
KMutexAbandon(mnt_list_lock);
if (ret < 0) {
free(mp->mnt_point);
free(mp);
}
return ret;
}
int UnmountFileSystem(const char *path)
{
size_t mnt_point_len;
struct MountPoint *mp = NULL, *itr;
struct SysDoubleLinklistNode *node;
int ret = -EINVAL;
if (path == NULL || path[0] != '/') {
SYS_ERR("%s: invalid mount point\n", __func__);
return -EINVAL;
}
mnt_point_len = strlen(path);
KMutexObtain(mnt_list_lock, WAITING_FOREVER);
DOUBLE_LINKLIST_FOR_EACH(node, &mnt_list) {
itr =CONTAINER_OF(node, struct MountPoint, node);
if (itr->mnt_point_len != mnt_point_len)
continue;
if (strncmp(itr->mnt_point, path, mnt_point_len) == 0) {
mp = itr;
break;
}
}
if (mp == NULL) {
SYS_ERR("%s: no mount point found on %s\n", __func__, path);
ret = -EINVAL;
goto err;
}
if (mp->fs->unmount == NULL) {
SYS_ERR("%s: specified file system does not have unmount function",
__func__);
ret = -EINVAL;
goto err;
}
ret = mp->fs->unmount(mp);
if (ret < 0) {
SYS_ERR("%s: filesystem unmount failed\n", __func__);
goto err;
}
DoubleLinkListRmNode(&mp->node);
if (mp->dev != NULL)
BusDevClose(mp->dev);
free(mp->mnt_point);
free(mp);
DBG("%s: filesystem unmounted from %s\n", __func__, path);
err:
KMutexAbandon(mnt_list_lock);
return ret;
}
int RegisterFilesystem(enum FilesystemType fs_type,
struct Filesystem *fs)
{
if (fs_type >= FSTYPE_END)
return -EINVAL;
fstable[fs_type] = fs;
return 0;
}
void SyncOpenedFiles()
{
struct FileDescriptor *fdp;
for (int i = 0; i < FD_MAX - FD_OFFSET; i++) {
fdp = fdtable[i];
if (fdp != NULL)
if (fdp->mntp->fs->sync != NULL)
fdp->mntp->fs->sync(fdp);
}
}
int open(const char *path, int flags, ...)
{
int fd, ret;
struct FileDescriptor *fdp;
struct MountPoint *mp;
char *abspath, *relpath;
if (path == NULL) {
SYS_ERR("%s: invalid file name\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
fd = NewFileDescriptor(&fdp);
if (fd < 0) {
KUpdateExstatus(ENOMEM);
return -1;
}
abspath = GetAbsolutePath(path);
mp = GetMountPoint(abspath);
if (mp == NULL) {
SYS_ERR("%s: mount point not found\n", __func__);
ret = -EINVAL;
goto err;
}
relpath = GetRelativePath(mp->mnt_point, abspath);
fdp->type = FTYPE_FILE;
fdp->mntp = mp;
fdp->pos = 0;
fdp->path = strdup(abspath);
if (fdp->path == NULL) {
SYS_ERR("%s: memory not enough\n", __func__);
ret = -ENOMEM;
goto err;
}
if (mp->fs->open == NULL) {
SYS_ERR("%s: no open function found\n", __func__);
ret = -EINVAL;
goto err;
}
ret = mp->fs->open(fdp, relpath);
if (ret < 0) {
SYS_ERR("%s: file open failed\n", __func__);
goto err;
}
if (flags & O_TRUNC)
ftruncate(fd, 0);
if (flags & O_APPEND)
lseek(fd, 0, SEEK_END);
err:
free(abspath);
if (ret < 0) {
FreeFileDescriptor(fdp);
KUpdateExstatus(ret);
return -1;
}
return fd;
}
int close(int fd)
{
int ret;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->close == NULL) {
SYS_ERR("%s: no close function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->close(fdp);
if (ret < 0) {
SYS_ERR("%s: close file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
FreeFileDescriptor(fdp);
return 0;
}
int read(int fd, void *buf, size_t len)
{
int ret;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->read == NULL) {
SYS_ERR("%s: no read function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->read(fdp, buf, len);
if (ret < 0) {
SYS_ERR("%s: read file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
return ret;
}
int write(int fd, const void *buf, size_t len)
{
int ret;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->write == NULL) {
SYS_ERR("%s: no write function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->write(fdp, buf, len);
if (ret < 0) {
SYS_ERR("%s: write file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
return ret;
}
#ifndef LIB_MUSLLIB
int ioctl(int fd, int cmd, ...)
{
int ret;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->ioctl == NULL) {
SYS_ERR("%s: no ioctl function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
va_list ap;
va_start(ap, cmd);
ret = fdp->mntp->fs->ioctl(fdp, cmd, (void*)va_arg(ap, long));
va_end(ap);
if (ret < 0) {
SYS_ERR("%s: ioctl file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
return ret;
}
#endif
off_t lseek(int fd, off_t offset, int whence)
{
int ret;
off_t new_offset;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->seek == NULL) {
SYS_ERR("%s: no seek function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->seek(fdp, offset, whence, &new_offset);
if (ret < 0) {
SYS_ERR("%s: seek file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
return new_offset;
}
int rename(const char *from, const char *to)
{
struct MountPoint *mp_from, *mp_to;
char *abs_from, *abs_to, *rel_from, *rel_to;
int ret = -EINVAL;
if (from == NULL || to == NULL) {
SYS_ERR("%s: invalid file name\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
abs_from = GetAbsolutePath(from);
abs_to = GetAbsolutePath(to);
mp_from = GetMountPoint(abs_from);
mp_to = GetMountPoint(abs_to);
if (mp_from == NULL || mp_from != mp_to) {
SYS_ERR("%s: paths not under the same mount point\n", __func__);
goto err;
}
rel_from = GetRelativePath(mp_from->mnt_point, abs_from);
rel_to = GetRelativePath(mp_to->mnt_point, abs_to);
if (mp_from->fs->rename == NULL) {
SYS_ERR("%s: no rename function found\n", __func__);
goto err;
}
ret = mp_from->fs->rename(mp_from, rel_from, rel_to);
if (ret < 0) {
SYS_ERR("%s: rename file failed\n", __func__);
goto err;
}
err:
free(abs_from);
free(abs_to);
if (ret < 0) {
KUpdateExstatus(ret);
return -1;
}
return 0;
}
int unlink(const char *path)
{
struct MountPoint *mp;
char *abspath, *relpath;
int ret = -EINVAL;
if (path == NULL) {
SYS_ERR("%s: invalid path\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
abspath = GetAbsolutePath(path);
mp = GetMountPoint(abspath);
if (mp == NULL) {
SYS_ERR("%s: no mount point found\n", __func__);
goto err;
}
relpath = GetRelativePath(mp->mnt_point, abspath);
if (mp->fs->unlink == NULL) {
SYS_ERR("%s: no unlink function found\n", __func__);
goto err;
}
ret = mp->fs->unlink(mp, relpath);
if (ret < 0) {
SYS_ERR("%s: unlink file failed\n", ret);
goto err;
}
err:
free(abspath);
if (ret < 0) {
KUpdateExstatus(ret);
return -1;
}
return 0;
}
int stat(const char *path, struct stat *buf)
{
struct FileStat vfs_statbuf;
struct MountPoint *mp;
char *abspath, *relpath;
int ret = -EINVAL;
if (path == NULL) {
SYS_ERR("%s: invalid path\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
abspath = GetAbsolutePath(path);
if (strcmp(abspath, "/") == 0) {
buf->st_dev = 0;
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH |
S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
buf->st_size = 0;
buf->st_mtime = 0;
ret = 0;
goto err;
}
mp = GetMountPoint(abspath);
if (mp == NULL) {
// if (strcmp(abspath, "/") == 0) {
// /* vfs root directory, no fs mounted */
// buf->st_dev = 0;
// buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
// S_IWUSR | S_IWGRP | S_IWOTH |
// S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
// buf->st_size = 0;
// buf->st_mtime = 0;
// ret = 0;
// goto err;
// }
SYS_ERR("%s: no mount point found\n", __func__);
goto err;
}
relpath = GetRelativePath(mp->mnt_point, abspath);
if (mp->fs->stat == NULL) {
SYS_ERR("%s: no stat function found\n", __func__);
goto err;
}
ret = mp->fs->stat(mp, relpath, &vfs_statbuf);
if (ret < 0) {
SYS_ERR("%s: stat file failed\n", __func__);
goto err;
}
buf->st_dev = 0;
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
if (vfs_statbuf.type == FTYPE_DIR)
buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
else
buf->st_mode |= S_IFREG;
buf->st_size = vfs_statbuf.size;
buf->st_mtime = vfs_statbuf.mtime;
err:
free(abspath);
if (ret < 0) {
KUpdateExstatus(ret);
return -1;
}
return 0;
}
int fstat(int fd, struct stat *buf)
{
int ret;
struct FileDescriptor *fdp;
char *relpath;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
return stat(fdp->path, buf);
}
int fsync(int fd)
{
int ret;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->sync == NULL) {
SYS_ERR("%s: no sync function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->sync(fdp);
if (ret < 0) {
SYS_ERR("%s: sync file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
return ret;
}
int ftruncate(int fd, off_t length)
{
int ret;
struct FileDescriptor *fdp;
fdp = GetFileDescriptor(fd);
if (fdp == NULL) {
KUpdateExstatus(EBADF);
return -1;
}
if (fdp->mntp->fs->truncate == NULL) {
SYS_ERR("%s: no truncate function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->truncate(fdp, length);
if (ret < 0) {
SYS_ERR("%s: truncate file failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
return ret;
}
int mkdir(const char *path, mode_t mode)
{
struct MountPoint *mp;
char *abspath, *relpath;
int ret = -EINVAL;
if (path == NULL) {
SYS_ERR("%s: invalid path\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
abspath = GetAbsolutePath(path);
mp = GetMountPoint(abspath);
if (mp == NULL) {
SYS_ERR("%s: no mount point found\n", __func__);
goto err;
}
relpath = GetRelativePath(mp->mnt_point, abspath);
if (mp->fs->mkdir == NULL) {
SYS_ERR("%s: no mkdir function found\n", __func__);
goto err;
}
ret = mp->fs->mkdir(mp, relpath);
if (ret < 0) {
SYS_ERR("%s: mkdir failed\n", ret);
goto err;
}
err:
free(abspath);
if (ret < 0) {
KUpdateExstatus(ret);
return -1;
}
return 0;
}
DIR *opendir(const char *path)
{
struct FileDescriptor *fdp;
struct MountPoint *mp;
char *abspath, *relpath;
int ret = -EINVAL;
if (path == NULL) {
SYS_ERR("%s: invalid path\n", __func__);
KUpdateExstatus(EINVAL);
return NULL;
}
fdp = malloc(sizeof(struct FileDescriptor));
if (fdp == NULL) {
SYS_ERR("%s: memory not enough\n", __func__);
KUpdateExstatus(ENOMEM);
return NULL;
}
memset(fdp, 0, sizeof(struct FileDescriptor));
abspath = GetAbsolutePath(path);
mp = GetMountPoint(abspath);
if (mp == NULL) {
SYS_ERR("%s: no mount point found\n", __func__);
goto err;
}
relpath = GetRelativePath(mp->mnt_point, abspath);
fdp->type = FTYPE_DIR;
fdp->mntp = mp;
fdp->pos = 0;
fdp->path = strdup(abspath);
if (fdp->path == NULL) {
SYS_ERR("%s: memory not enough\n", __func__);
ret = -ENOMEM;
goto err;
}
if (mp->fs->opendir == NULL) {
SYS_ERR("%s: no opendir function found\n", __func__);
goto err;
}
ret = mp->fs->opendir(fdp, relpath);
if (ret < 0) {
SYS_ERR("%s: opendir failed\n", __func__);
goto err;
}
err:
free(abspath);
if (ret < 0) {
free(fdp->path);
free(fdp);
KUpdateExstatus(ret);
return NULL;
}
return fdp;
}
int closedir(DIR *dirp)
{
struct FileDescriptor *fdp = dirp;
int ret;
if (fdp == NULL) {
SYS_ERR("%s: invalid directory pointer\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
if (fdp->mntp->fs->closedir == NULL) {
SYS_ERR("%s: no closedir function found\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
ret = fdp->mntp->fs->closedir(fdp);
if (ret < 0) {
SYS_ERR("%s: closedir failed\n", __func__);
KUpdateExstatus(ret);
return -1;
}
free(fdp->path);
free(fdp);
return 0;
}
static struct dirent dirent;
struct dirent *readdir(DIR *dirp)
{
struct FileDescriptor *fdp = dirp;
int ret;
if (fdp == NULL) {
SYS_ERR("%s: invalid directory pointer\n", __func__);
KUpdateExstatus(EINVAL);
return NULL;
}
if (fdp->mntp->fs->readdir == NULL) {
SYS_ERR("%s: no readdir function found\n", __func__);
KUpdateExstatus(EINVAL);
return NULL;
}
ret = fdp->mntp->fs->readdir(fdp, &dirent);
if (ret < 0) {
SYS_ERR("%s: readdir failed\n", __func__);
KUpdateExstatus(ret);
return NULL;
}
if (dirent.d_name[0] == '\0')
return NULL;
return &dirent;
}
int rmdir(const char *path)
{
return unlink(path);
}
int chdir(const char *path)
{
char *abspath;
DIR *dirp;
if (path == NULL) {
SYS_ERR("%s: invalid path\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
dirp = opendir(path);
if (dirp == NULL) {
SYS_ERR("%s: chdir failed\n", __func__);
KUpdateExstatus(ENOTDIR);
return -1;
}
closedir(dirp);
abspath = GetAbsolutePath(path);
KMutexObtain(working_dir_lock, WAITING_FOREVER);
strcpy(working_dir, abspath);
KMutexAbandon(working_dir_lock);
free(abspath);
return 0;
}
char *getcwd(char *buf, size_t size)
{
KMutexObtain(working_dir_lock, WAITING_FOREVER);
strncpy(buf, working_dir, size - 1);
KMutexAbandon(working_dir_lock);
buf[size - 1] = '\0';
return buf;
}
void seekdir(DIR *dirp, off_t offset)
{
struct FileDescriptor *fdp = dirp;
if (fdp == NULL) {
SYS_ERR("%s: invalid directory pointer\n", __func__);
KUpdateExstatus(EINVAL);
return;
}
if (fdp->mntp->fs->seekdir == NULL) {
SYS_ERR("%s: no seekdir function found\n", __func__);
KUpdateExstatus(EINVAL);
return;
}
fdp->mntp->fs->seekdir(fdp, offset);
}
void rewinddir(DIR *dirp)
{
struct FileDescriptor *fdp = dirp;
if (fdp == NULL) {
SYS_ERR("%s: invalid directory pointer\n", __func__);
KUpdateExstatus(EINVAL);
return;
}
if (fdp->mntp->fs->seekdir == NULL) {
SYS_ERR("%s: no seekdir function found\n", __func__);
KUpdateExstatus(EINVAL);
return;
}
fdp->mntp->fs->seekdir(fdp, 0);
}
int statfs(const char *path, struct statfs *buf)
{
struct MountPoint *mp;
char *abspath, *relpath;
int ret = -EINVAL;
if (path == NULL) {
SYS_ERR("%s: invalid path\n", __func__);
KUpdateExstatus(EINVAL);
return -1;
}
abspath = GetAbsolutePath(path);
mp = GetMountPoint(abspath);
if (mp == NULL) {
SYS_ERR("%s: no mount point found\n", __func__);
goto err;
}
relpath = GetRelativePath(mp->mnt_point, abspath);
if (mp->fs->statvfs == NULL) {
SYS_ERR("%s: no statvfs function found\n", __func__);
goto err;
}
ret = mp->fs->statvfs(mp, relpath, buf);
if (ret < 0) {
SYS_ERR("%s: statfs failed\n", __func__);
goto err;
}
err:
free(abspath);
if (ret < 0) {
KUpdateExstatus(ret);
return -1;
}
return 0;
}
int VfsInit()
{
InitDoubleLinkList(&mnt_list);
mnt_list_lock = KMutexCreate();
working_dir_lock = KMutexCreate();
fdtable_lock = KMutexCreate();
strcpy(working_dir, "/");
extern int DevicefileInit();
DevicefileInit();
MountFilesystem(NULL, NULL, NULL, FSTYPE_IOTDEVICEFILE, "/dev");
return 0;
}
int ShowFd()
{
for (int i = 0; i < FD_MAX - FD_OFFSET; i++) {
struct FileDescriptor *fdp = fdtable[i];
if (fdp == NULL)
continue;
KPrintf("%d ", i + FD_OFFSET);
if (fdp->type == FTYPE_DIR)
KPrintf("DIR ");
else
KPrintf("FILE ");
KPrintf("%s\n", fdp->path);
}
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),ShowFd, ShowFd, show file descriptor );