forked from xuos/xiuos
1188 lines
26 KiB
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 );
|