os_kernel_lab/code/lab8/kern/fs/sysfile.c

318 lines
6.6 KiB
C

#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;
}