summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-02-22 02:18:33 -0500
committerIan Moffett <ian@osmora.org>2025-02-22 02:20:12 -0500
commitd68537c1ca22d58f1c219d970d5aa462df9e0c6b (patch)
tree375e9f1a9feb249f39754a8df38f5fdfe4430b85
parent2f7f296f8e7eae3944bc34e9dfe51a262b7f7149 (diff)
kernel: vfs: Add support for write()
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r--lib/libc/include/unistd.h1
-rw-r--r--lib/libc/src/unistd/write.c38
-rw-r--r--sys/fs/initramfs.c1
-rw-r--r--sys/include/sys/fcntl.h5
-rw-r--r--sys/include/sys/filedesc.h2
-rw-r--r--sys/include/sys/syscall.h1
-rw-r--r--sys/include/sys/vfs.h1
-rw-r--r--sys/include/sys/vnode.h2
-rw-r--r--sys/kern/kern_descrip.c50
-rw-r--r--sys/kern/kern_syscall.c1
-rw-r--r--sys/kern/vfs_subr.c13
-rw-r--r--sys/kern/vfs_syscalls.c12
12 files changed, 120 insertions, 7 deletions
diff --git a/lib/libc/include/unistd.h b/lib/libc/include/unistd.h
index 50d6800..c487d38 100644
--- a/lib/libc/include/unistd.h
+++ b/lib/libc/include/unistd.h
@@ -36,6 +36,7 @@
__BEGIN_DECLS
ssize_t read(int fd, void *buf, size_t count);
+ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
__END_DECLS
diff --git a/lib/libc/src/unistd/write.c b/lib/libc/src/unistd/write.c
new file mode 100644
index 0000000..2672016
--- /dev/null
+++ b/lib/libc/src/unistd/write.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+ssize_t
+write(int fd, const void *buf, size_t count)
+{
+ return syscall(SYS_write, fd, (uintptr_t)buf, count);
+}
diff --git a/sys/fs/initramfs.c b/sys/fs/initramfs.c
index acef462..fd746ef 100644
--- a/sys/fs/initramfs.c
+++ b/sys/fs/initramfs.c
@@ -275,6 +275,7 @@ initramfs_init(struct fs_info *fip)
const struct vops g_initramfs_vops = {
.lookup = initramfs_lookup,
.read = initramfs_read,
+ .write = NULL,
.reclaim = initramfs_reclaim,
.getattr = initramfs_getattr
};
diff --git a/sys/include/sys/fcntl.h b/sys/include/sys/fcntl.h
index 7a62cdd..122a378 100644
--- a/sys/include/sys/fcntl.h
+++ b/sys/include/sys/fcntl.h
@@ -34,4 +34,9 @@
#define O_WRONLY 0x0001
#define O_RDWR 0x0002
+/* Makes seal checking easier */
+#if defined(_KERNEL)
+#define O_ALLOW_WR (O_RDWR | O_WRONLY)
+#endif
+
#endif /* !_SYS_FCTNL_H_ */
diff --git a/sys/include/sys/filedesc.h b/sys/include/sys/filedesc.h
index 9a6230a..a544811 100644
--- a/sys/include/sys/filedesc.h
+++ b/sys/include/sys/filedesc.h
@@ -39,12 +39,14 @@ struct filedesc {
off_t offset;
bool is_dir;
int refcnt;
+ int flags;
struct vnode *vp;
struct spinlock lock;
};
int fd_close(unsigned int fd);
int fd_read(unsigned int fd, void *buf, size_t count);
+int fd_write(unsigned int fd, void *buf, size_t count);
int fd_alloc(struct filedesc **fd_out);
int fd_open(const char *pathname, int flags);
diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h
index b724e8b..41d1e78 100644
--- a/sys/include/sys/syscall.h
+++ b/sys/include/sys/syscall.h
@@ -42,6 +42,7 @@
#define SYS_close 4
#define SYS_stat 5
#define SYS_sysctl 6
+#define SYS_write 7
#if defined(_KERNEL)
/* Syscall return value and arg type */
diff --git a/sys/include/sys/vfs.h b/sys/include/sys/vfs.h
index 61f6673..1ff722a 100644
--- a/sys/include/sys/vfs.h
+++ b/sys/include/sys/vfs.h
@@ -38,6 +38,7 @@
scret_t sys_open(struct syscall_args *scargs);
scret_t sys_close(struct syscall_args *args);
scret_t sys_read(struct syscall_args *scargs);
+scret_t sys_write(struct syscall_args *sargs);
scret_t sys_stat(struct syscall_args *scargs);
#endif /* _KERNEL */
diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h
index 5cbaa15..33092f9 100644
--- a/sys/include/sys/vnode.h
+++ b/sys/include/sys/vnode.h
@@ -101,6 +101,7 @@ struct vops {
int(*lookup)(struct vop_lookup_args *args);
int(*getattr)(struct vop_getattr_args *args);
int(*read)(struct vnode *vp, struct sio_txn *sio);
+ int(*write)(struct vnode *vp, struct sio_txn *sio);
int(*reclaim)(struct vnode *vp);
};
@@ -117,6 +118,7 @@ int vfs_release_vnode(struct vnode *vp);
int vfs_vop_lookup(struct vnode *vp, struct vop_lookup_args *args);
int vfs_vop_read(struct vnode *vp, struct sio_txn *sio);
+int vfs_vop_write(struct vnode *vp, struct sio_txn *sio);
int vfs_vop_getattr(struct vnode *vp, struct vop_getattr_args *args);
#endif /* _KERNEL */
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index d1ed044..201db3e 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -31,6 +31,7 @@
#include <sys/errno.h>
#include <sys/proc.h>
#include <sys/limits.h>
+#include <sys/fcntl.h>
#include <sys/namei.h>
#include <sys/filedesc.h>
#include <sys/systm.h>
@@ -135,15 +136,16 @@ fd_close(unsigned int fd)
}
/*
- * Read bytes from a file using a file
+ * Read/write bytes to/from a file using a file
* descriptor number.
*
* @fd: File descriptor number.
- * @buf: Buffer to read into.
+ * @buf: Buffer with data to read/write
* @count: Number of bytes to read.
+ * @write: Set to 1 for writes
*/
-int
-fd_read(unsigned int fd, void *buf, size_t count)
+static int
+fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write)
{
char *kbuf = NULL;
struct filedesc *filedes;
@@ -173,13 +175,34 @@ fd_read(unsigned int fd, void *buf, size_t count)
goto done;
}
+ /* Check if this violates the file seal */
+ if (!ISSET(filedes->flags, O_ALLOW_WR) && write) {
+ return -EPERM;
+ } else if (ISSET(O_RDONLY, filedes->flags) && write) {
+ return -EPERM;
+ }
+
sio.len = count;
sio.buf = kbuf;
sio.offset = filedes->offset;
- if ((count = vfs_vop_read(filedes->vp, &sio)) < 0) {
- retval = -EIO;
- goto done;
+ if (write) {
+ /* Copy in user buffer */
+ if (copyin(buf, kbuf, count) < 0) {
+ retval = -EFAULT;
+ goto done;
+ }
+
+ /* Call VFS write hook */
+ if ((count = vfs_vop_write(filedes->vp, &sio)) < 0) {
+ retval = -EIO;
+ goto done;
+ }
+ } else {
+ if ((count = vfs_vop_read(filedes->vp, &sio)) < 0) {
+ retval = -EIO;
+ goto done;
+ }
}
if (copyout(kbuf, buf, count) < 0) {
@@ -195,6 +218,18 @@ done:
return retval;
}
+int
+fd_read(unsigned int fd, void *buf, size_t count)
+{
+ return fd_rw(fd, buf, count, 0);
+}
+
+int
+fd_write(unsigned int fd, void *buf, size_t count)
+{
+ return fd_rw(fd, buf, count, 1);
+}
+
/*
* Open a file and get a file descriptor
* number.
@@ -224,6 +259,7 @@ fd_open(const char *pathname, int flags)
}
filedes->vp = nd.vp;
+ filedes->flags = flags;
return filedes->fdno;
}
diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c
index 1d961a7..986d82a 100644
--- a/sys/kern/kern_syscall.c
+++ b/sys/kern/kern_syscall.c
@@ -41,6 +41,7 @@ scret_t(*g_sctab[])(struct syscall_args *) = {
sys_close, /* SYS_close */
sys_stat, /* SYS_stat */
sys_sysctl, /* SYS_sysctl */
+ sys_write, /* SYS_write */
};
const size_t MAX_SYSCALLS = NELEM(g_sctab);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index f67bcfe..da0a4f9 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -167,6 +167,19 @@ vfs_vop_read(struct vnode *vp, struct sio_txn *sio)
}
int
+vfs_vop_write(struct vnode *vp, struct sio_txn *sio)
+{
+ const struct vops *vops = vp->vops;
+
+ if (vops == NULL)
+ return -EIO;
+ if (vops->write == NULL)
+ return -EIO;
+
+ return vops->write(vp, sio);
+}
+
+int
vfs_vop_getattr(struct vnode *vp, struct vop_getattr_args *args)
{
const struct vops *vops = vp->vops;
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index fa613c2..6f2d683 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -129,6 +129,18 @@ sys_read(struct syscall_args *scargs)
}
/*
+ * arg0: fd
+ * arg1: buf
+ * arg2: count
+ */
+scret_t
+sys_write(struct syscall_args *scargs)
+{
+ return fd_write(scargs->arg0, (void *)scargs->arg1,
+ scargs->arg2);
+}
+
+/*
* arg0: path
* arg1: buf
*/