summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/include/sys/filedesc.h2
-rw-r--r--sys/include/sys/syscall.h1
-rw-r--r--sys/kern/kern_filedesc.c67
-rw-r--r--sys/kern/kern_syscall.c1
4 files changed, 71 insertions, 0 deletions
diff --git a/sys/include/sys/filedesc.h b/sys/include/sys/filedesc.h
index e0835a5..70b297d 100644
--- a/sys/include/sys/filedesc.h
+++ b/sys/include/sys/filedesc.h
@@ -55,10 +55,12 @@ struct filedesc *fd_from_fdnum(const struct proc *td, int fdno);
void fd_close_fdnum(struct proc *td, int fdno);
ssize_t write(int fd, const void *buf, size_t count);
int open(const char *pathname, int oflag);
+int read(int fd, void *buf, size_t count);
uint64_t sys_write(struct syscall_args *args);
uint64_t sys_open(struct syscall_args *args);
uint64_t sys_close(struct syscall_args *args);
+uint64_t sys_read(struct syscall_args *args);
#endif
#endif
diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h
index 5020d3a..ae2438f 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -41,6 +41,7 @@ enum {
SYS_write,
SYS_open,
SYS_close,
+ SYS_read,
__MAX_SYSCALLS
};
diff --git a/sys/kern/kern_filedesc.c b/sys/kern/kern_filedesc.c
index 6f59508..c610747 100644
--- a/sys/kern/kern_filedesc.c
+++ b/sys/kern/kern_filedesc.c
@@ -298,6 +298,36 @@ open(const char *pathname, int oflag)
}
/*
+ * Read file into a buffer.
+ *
+ * @fd: File descriptor number.
+ * @buf: Buffer to read to.
+ * @count: Number of bytes to read.
+ */
+int
+read(int fd, void *buf, size_t count)
+{
+ ssize_t bytes_read;
+ struct vnode *vnode;
+ struct filedesc *fd_desc;
+
+ fd_desc = fd_from_fdnum(this_td(), fd);
+
+ if (fd_desc == NULL) {
+ return -EBADF;
+ }
+
+ vnode = fd_desc->vnode;
+
+ if (count > MAX_RW_SIZE) {
+ return -EINVAL;
+ }
+
+ bytes_read = vfs_read(vnode, buf, count);
+ return bytes_read;
+}
+
+/*
* arg0: int fd
* arg1: const void *buf
* arg2: count
@@ -340,3 +370,40 @@ sys_close(struct syscall_args *args)
fd_close_fdnum(this_td(), args->arg0);
return 0;
}
+
+/*
+ * arg0: fd
+ * arg1: char *buf
+ * arg2: size_t count
+ */
+uint64_t
+sys_read(struct syscall_args *args)
+{
+ char *kbuf;
+ ssize_t bytes_read;
+
+ if (args->arg2 > MAX_RW_SIZE || args->arg2 == 0) {
+ return -EINVAL;
+ }
+
+ kbuf = dynalloc(args->arg2);
+
+ if (kbuf == NULL) {
+ return -ENOMEM;
+ }
+
+ /*
+ * Try to read into our kernel buffer then copy out
+ * to userspace.
+ */
+ if ((bytes_read = read(args->arg0, kbuf, args->arg2)) < 0) {
+ /* Failure */
+ dynfree(kbuf);
+ return bytes_read;
+ }
+
+ if (copyout(kbuf, args->arg1, bytes_read) != 0) {
+ invalid_uaddr(args->arg1);
+ }
+ return bytes_read;
+}
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index 4acfdc5..0f45469 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -45,4 +45,5 @@ uint64_t(*g_syscall_table[__MAX_SYSCALLS])(struct syscall_args *args) = {
sys_write,
sys_open,
sys_close,
+ sys_read,
};