#include <defs.h>
|
|
#include <string.h>
|
|
#include <vmm.h>
|
|
#include <proc.h>
|
|
#include <kmalloc.h>
|
|
#include <vfs.h>
|
|
#include <file.h>
|
|
#include <iobuf.h>
|
|
#include <sysfile.h>
|
|
#include <stat.h>
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
#include <error.h>
|
|
#include <assert.h>
|
|
|
|
#define IOBUF_SIZE 4096
|
|
|
|
/* copy_path - copy path name */
|
|
static int
|
|
copy_path(char **to, const char *from) {
|
|
struct mm_struct *mm = current->mm;
|
|
char *buffer;
|
|
if ((buffer = kmalloc(FS_MAX_FPATH_LEN + 1)) == NULL) {
|
|
return -E_NO_MEM;
|
|
}
|
|
lock_mm(mm);
|
|
if (!copy_string(mm, buffer, from, FS_MAX_FPATH_LEN + 1)) {
|
|
unlock_mm(mm);
|
|
goto failed_cleanup;
|
|
}
|
|
unlock_mm(mm);
|
|
*to = buffer;
|
|
return 0;
|
|
|
|
failed_cleanup:
|
|
kfree(buffer);
|
|
return -E_INVAL;
|
|
}
|
|
|
|
/* sysfile_open - open file */
|
|
int
|
|
sysfile_open(const char *__path, uint32_t open_flags) {
|
|
int ret;
|
|
char *path;
|
|
if ((ret = copy_path(&path, __path)) != 0) {
|
|
return ret;
|
|
}
|
|
ret = file_open(path, open_flags);
|
|
kfree(path);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_close - close file */
|
|
int
|
|
sysfile_close(int fd) {
|
|
return file_close(fd);
|
|
}
|
|
|
|
/* sysfile_read - read file */
|
|
int
|
|
sysfile_read(int fd, void *base, size_t len) {
|
|
struct mm_struct *mm = current->mm;
|
|
if (len == 0) {
|
|
return 0;
|
|
}
|
|
if (!file_testfd(fd, 1, 0)) {
|
|
return -E_INVAL;
|
|
}
|
|
void *buffer;
|
|
if ((buffer = kmalloc(IOBUF_SIZE)) == NULL) {
|
|
return -E_NO_MEM;
|
|
}
|
|
|
|
int ret = 0;
|
|
size_t copied = 0, alen;
|
|
while (len != 0) {
|
|
if ((alen = IOBUF_SIZE) > len) {
|
|
alen = len;
|
|
}
|
|
ret = file_read(fd, buffer, alen, &alen);
|
|
if (alen != 0) {
|
|
lock_mm(mm);
|
|
{
|
|
if (copy_to_user(mm, base, buffer, alen)) {
|
|
assert(len >= alen);
|
|
base += alen, len -= alen, copied += alen;
|
|
}
|
|
else if (ret == 0) {
|
|
ret = -E_INVAL;
|
|
}
|
|
}
|
|
unlock_mm(mm);
|
|
}
|
|
if (ret != 0 || alen == 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
kfree(buffer);
|
|
if (copied != 0) {
|
|
return copied;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_write - write file */
|
|
int
|
|
sysfile_write(int fd, void *base, size_t len) {
|
|
struct mm_struct *mm = current->mm;
|
|
if (len == 0) {
|
|
return 0;
|
|
}
|
|
if (!file_testfd(fd, 0, 1)) {
|
|
return -E_INVAL;
|
|
}
|
|
void *buffer;
|
|
if ((buffer = kmalloc(IOBUF_SIZE)) == NULL) {
|
|
return -E_NO_MEM;
|
|
}
|
|
|
|
int ret = 0;
|
|
size_t copied = 0, alen;
|
|
while (len != 0) {
|
|
if ((alen = IOBUF_SIZE) > len) {
|
|
alen = len;
|
|
}
|
|
lock_mm(mm);
|
|
{
|
|
if (!copy_from_user(mm, buffer, base, alen, 0)) {
|
|
ret = -E_INVAL;
|
|
}
|
|
}
|
|
unlock_mm(mm);
|
|
if (ret == 0) {
|
|
ret = file_write(fd, buffer, alen, &alen);
|
|
if (alen != 0) {
|
|
assert(len >= alen);
|
|
base += alen, len -= alen, copied += alen;
|
|
}
|
|
}
|
|
if (ret != 0 || alen == 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
kfree(buffer);
|
|
if (copied != 0) {
|
|
return copied;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_seek - seek file */
|
|
int
|
|
sysfile_seek(int fd, off_t pos, int whence) {
|
|
return file_seek(fd, pos, whence);
|
|
}
|
|
|
|
/* sysfile_fstat - stat file */
|
|
int
|
|
sysfile_fstat(int fd, struct stat *__stat) {
|
|
struct mm_struct *mm = current->mm;
|
|
int ret;
|
|
struct stat __local_stat, *stat = &__local_stat;
|
|
if ((ret = file_fstat(fd, stat)) != 0) {
|
|
return ret;
|
|
}
|
|
|
|
lock_mm(mm);
|
|
{
|
|
if (!copy_to_user(mm, __stat, stat, sizeof(struct stat))) {
|
|
ret = -E_INVAL;
|
|
}
|
|
}
|
|
unlock_mm(mm);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_fsync - sync file */
|
|
int
|
|
sysfile_fsync(int fd) {
|
|
return file_fsync(fd);
|
|
}
|
|
|
|
/* sysfile_chdir - change dir */
|
|
int
|
|
sysfile_chdir(const char *__path) {
|
|
int ret;
|
|
char *path;
|
|
if ((ret = copy_path(&path, __path)) != 0) {
|
|
return ret;
|
|
}
|
|
ret = vfs_chdir(path);
|
|
kfree(path);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_link - link file */
|
|
int
|
|
sysfile_link(const char *__path1, const char *__path2) {
|
|
int ret;
|
|
char *old_path, *new_path;
|
|
if ((ret = copy_path(&old_path, __path1)) != 0) {
|
|
return ret;
|
|
}
|
|
if ((ret = copy_path(&new_path, __path2)) != 0) {
|
|
kfree(old_path);
|
|
return ret;
|
|
}
|
|
ret = vfs_link(old_path, new_path);
|
|
kfree(old_path), kfree(new_path);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_rename - rename file */
|
|
int
|
|
sysfile_rename(const char *__path1, const char *__path2) {
|
|
int ret;
|
|
char *old_path, *new_path;
|
|
if ((ret = copy_path(&old_path, __path1)) != 0) {
|
|
return ret;
|
|
}
|
|
if ((ret = copy_path(&new_path, __path2)) != 0) {
|
|
kfree(old_path);
|
|
return ret;
|
|
}
|
|
ret = vfs_rename(old_path, new_path);
|
|
kfree(old_path), kfree(new_path);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_unlink - unlink file */
|
|
int
|
|
sysfile_unlink(const char *__path) {
|
|
int ret;
|
|
char *path;
|
|
if ((ret = copy_path(&path, __path)) != 0) {
|
|
return ret;
|
|
}
|
|
ret = vfs_unlink(path);
|
|
kfree(path);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_get cwd - get current working directory */
|
|
int
|
|
sysfile_getcwd(char *buf, size_t len) {
|
|
struct mm_struct *mm = current->mm;
|
|
if (len == 0) {
|
|
return -E_INVAL;
|
|
}
|
|
|
|
int ret = -E_INVAL;
|
|
lock_mm(mm);
|
|
{
|
|
if (user_mem_check(mm, (uintptr_t)buf, len, 1)) {
|
|
struct iobuf __iob, *iob = iobuf_init(&__iob, buf, len, 0);
|
|
ret = vfs_getcwd(iob);
|
|
}
|
|
}
|
|
unlock_mm(mm);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_getdirentry - get the file entry in DIR */
|
|
int
|
|
sysfile_getdirentry(int fd, struct dirent *__direntp) {
|
|
struct mm_struct *mm = current->mm;
|
|
struct dirent *direntp;
|
|
if ((direntp = kmalloc(sizeof(struct dirent))) == NULL) {
|
|
return -E_NO_MEM;
|
|
}
|
|
|
|
int ret = 0;
|
|
lock_mm(mm);
|
|
{
|
|
if (!copy_from_user(mm, &(direntp->offset), &(__direntp->offset), sizeof(direntp->offset), 1)) {
|
|
ret = -E_INVAL;
|
|
}
|
|
}
|
|
unlock_mm(mm);
|
|
|
|
if (ret != 0 || (ret = file_getdirentry(fd, direntp)) != 0) {
|
|
goto out;
|
|
}
|
|
|
|
lock_mm(mm);
|
|
{
|
|
if (!copy_to_user(mm, __direntp, direntp, sizeof(struct dirent))) {
|
|
ret = -E_INVAL;
|
|
}
|
|
}
|
|
unlock_mm(mm);
|
|
|
|
out:
|
|
kfree(direntp);
|
|
return ret;
|
|
}
|
|
|
|
/* sysfile_dup - duplicate fd1 to fd2 */
|
|
int
|
|
sysfile_dup(int fd1, int fd2) {
|
|
return file_dup(fd1, fd2);
|
|
}
|
|
|
|
int
|
|
sysfile_pipe(int *fd_store) {
|
|
return -E_UNIMP;
|
|
}
|
|
|
|
int
|
|
sysfile_mkfifo(const char *__name, uint32_t open_flags) {
|
|
return -E_UNIMP;
|
|
}
|
|
|