diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libc/include/unistd.h | 10 | ||||
-rw-r--r-- | src/lib/libc/src/unistd/lseek.c | 47 | ||||
-rw-r--r-- | src/sys/fs/tmpfs.c | 115 | ||||
-rw-r--r-- | src/sys/include/compat/unix/syscall.h | 8 | ||||
-rw-r--r-- | src/sys/include/os/filedesc.h | 10 | ||||
-rw-r--r-- | src/sys/include/os/vnode.h | 21 | ||||
-rw-r--r-- | src/sys/include/sys/seek.h | 37 | ||||
-rw-r--r-- | src/sys/include/sys/syscall.h | 1 | ||||
-rw-r--r-- | src/sys/os/os_filedes.c | 53 | ||||
-rw-r--r-- | src/sys/os/vfs_subr.c | 20 |
10 files changed, 320 insertions, 2 deletions
diff --git a/src/lib/libc/include/unistd.h b/src/lib/libc/include/unistd.h index b668d5b..61b437c 100644 --- a/src/lib/libc/include/unistd.h +++ b/src/lib/libc/include/unistd.h @@ -30,6 +30,7 @@ #ifndef _UNISTD_H #define _UNISTD_H 1 +#include <sys/seek.h> #include <stddef.h> /* Standard stream file numbers */ @@ -74,4 +75,13 @@ ssize_t write(int fd, const void *buf, size_t count); */ ssize_t read(int fd, void *buf, size_t count); +/* + * Reposition the file offset of a file + * + * @fd: File descriptor to reposition + * @offset: Offset to move `fd' to + * @whence: How it should be repositioned + */ +off_t lseek(int fd, off_t offset, int whence); + #endif /* _UNISTD_H */ diff --git a/src/lib/libc/src/unistd/lseek.c b/src/lib/libc/src/unistd/lseek.c new file mode 100644 index 0000000..ade0a1e --- /dev/null +++ b/src/lib/libc/src/unistd/lseek.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * 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 the project 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 <unistd.h> +#include <errno.h> + +off_t +lseek(int fd, off_t offset, int whence) +{ + if (fd < 0) { + return -EBADF; + } + + return syscall( + SYS_lseek, + fd, + offset, + whence + ); +} diff --git a/src/sys/fs/tmpfs.c b/src/sys/fs/tmpfs.c index 4a5c607..af1537f 100644 --- a/src/sys/fs/tmpfs.c +++ b/src/sys/fs/tmpfs.c @@ -47,6 +47,7 @@ struct tmpfs_node { char name[TMPFS_NAMEMAX]; char *data; size_t len; + size_t real_len; int ref; TAILQ_ENTRY(tmpfs_node) link; }; @@ -93,6 +94,7 @@ tmpfs_new(const char *name, struct tmpfs_node **np_res) return -ENOMEM; } + np->real_len = 0; np->len = TMPFS_INIT_SIZE; np->ref = 1; memset(np->data, 0, TMPFS_INIT_SIZE); @@ -232,6 +234,114 @@ tmpfs_mount(struct fs_info *fip, struct mount_args *margs) return 0; } +/* + * Write to the filesystem + */ +static ssize_t +tmpfs_write(struct vop_rw_data *data) +{ + struct vnode *vp; + struct tmpfs_node *np; + char *dest; + void *p; + size_t node_len, len; + size_t overflow_window; + + if (data == NULL) { + return -EINVAL; + } + + if ((vp = data->vp) == NULL) { + return -EIO; + } + + /* We need the vnode for lengths */ + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* + * Check if there is going to be any overflows + * and if so, get the overflow window and expand + * the buffer by it. + */ + len = data->len; + if ((len + data->off) > np->len) { + overflow_window = (len + data->off) - np->len; + np->len += overflow_window + 1; + + p = np->data; + np->data = krealloc(np->data, np->len); + if (np->data == NULL) { + np->data = p; + return -ENOMEM; + } + } + + np->real_len += len; + node_len = np->len; + dest = np->data + data->off; + memcpy(dest, data->data, len); + return len; +} + +static ssize_t +tmpfs_read(struct vop_rw_data *data) +{ + struct vnode *vp; + struct tmpfs_node *np; + size_t len; + char *dest, *src; + + if (data == NULL) { + return -1; + } + + if ((vp = data->vp) == NULL) { + return -EIO; + } + + if ((np = vp->data) == NULL) { + return -EIO; + } + + /* Return EOF if the offset is too far */ + len = data->len; + if (data->off >= np->real_len) { + return 0; /* EOF */ + } + + /* Is there any data to read? */ + if ((len + data->off) > np->len) { + len = np->len; + } + if (len == 0) { + return 0; + } + + dest = data->data; + src = np->data + data->off; + memcpy(dest, src, len); + return len; +} + +static int +tmpfs_getattr(struct vnode *vp, struct vattr *res) +{ + struct tmpfs_node *np; + + if (vp == NULL || res == NULL) { + return -EINVAL; + } + + if ((np = vp->data) == NULL) { + return -EIO; + } + + res->size = np->real_len; + return 0; +} + static int tmpfs_reclaim(struct vnode *vp, int flags) { @@ -241,7 +351,10 @@ tmpfs_reclaim(struct vnode *vp, int flags) static struct vop tmpfs_vops = { .lookup = tmpfs_lookup, .create = tmpfs_create, - .reclaim = tmpfs_reclaim + .reclaim = tmpfs_reclaim, + .write = tmpfs_write, + .read = tmpfs_read, + .getattr = tmpfs_getattr }; struct vfsops g_tmpfs_vfsops = { diff --git a/src/sys/include/compat/unix/syscall.h b/src/sys/include/compat/unix/syscall.h index a031872..42dc4c0 100644 --- a/src/sys/include/compat/unix/syscall.h +++ b/src/sys/include/compat/unix/syscall.h @@ -73,6 +73,11 @@ scret_t sys_read(struct syscall_args *scargs); */ scret_t sys_close(struct syscall_args *scargs); +/* + * Seek a file descriptor + */ +scret_t sys_lseek(struct syscall_args *scargs); + #ifdef _NEED_UNIX_SCTAB scret_t(*g_unix_sctab[])(struct syscall_args *) = { [SYS_none] = NULL, @@ -89,7 +94,8 @@ scret_t(*g_unix_sctab[])(struct syscall_args *) = { [SYS_waitpid] = sys_waitpid, [SYS_dmsio] = sys_dmsio, [SYS_read] = sys_read, - [SYS_close] = sys_close + [SYS_close] = sys_close, + [SYS_lseek] = sys_lseek }; #endif /* !_NEED_UNIX_SCTAB */ diff --git a/src/sys/include/os/filedesc.h b/src/sys/include/os/filedesc.h index a6a2ac5..b773de9 100644 --- a/src/sys/include/os/filedesc.h +++ b/src/sys/include/os/filedesc.h @@ -30,6 +30,7 @@ #ifndef _OS_FILEDESC_H_ #define _OS_FILEDESC_H_ 1 +#include <sys/seek.h> #include <sys/types.h> #include <os/vnode.h> @@ -117,4 +118,13 @@ ssize_t write(int fd, const void *buf, size_t count); */ ssize_t read(int fd, void *buf, size_t count); +/* + * Reposition the file offset of a file + * + * @fd: File descriptor to reposition + * @offset: Offset to move `fd' to + * @whence: How it should be repositioned + */ +off_t lseek(int fd, off_t offset, int whence); + #endif /* !_OS_FILEDESC_H_ */ diff --git a/src/sys/include/os/vnode.h b/src/sys/include/os/vnode.h index 628ba68..77cadb2 100644 --- a/src/sys/include/os/vnode.h +++ b/src/sys/include/os/vnode.h @@ -94,10 +94,20 @@ struct vop_create_args { }; /* + * Represents attributes of a vnode + * + * @size: File size in bytes + */ +struct vattr { + size_t size; +}; + +/* * Represents operations that can be performed on * a specific vnode. These are implemented as callbacks */ struct vop { + int(*getattr)(struct vnode *vp, struct vattr *res); int(*lookup)(struct vop_lookup_args *args); int(*reclaim)(struct vnode *vp, int flags); int(*create)(struct vop_create_args *args); @@ -200,4 +210,15 @@ int vop_reclaim(struct vnode *vp, int flags); */ int vop_create(struct vnode *vp, struct nameidata *ndp); +/* + * Get the attributes of a file + * + * @vp: Vnode of file to get attributes of + * @res: Result of file to get attr of + * + * Returns zero on success, otherwise a less than + * zero value on failure + */ +int vop_getattr(struct vnode *vp, struct vattr *res); + #endif /* !_OS_VNODE_H_ */ diff --git a/src/sys/include/sys/seek.h b/src/sys/include/sys/seek.h new file mode 100644 index 0000000..1edc50b --- /dev/null +++ b/src/sys/include/sys/seek.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * 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 the project 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. + */ + +#ifndef _SYS_SEEK_H_ +#define _SYS_SEEK_H_ 1 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#endif /* !_SYS_SEEK_H_ */ diff --git a/src/sys/include/sys/syscall.h b/src/sys/include/sys/syscall.h index 77b7505..c97d5ea 100644 --- a/src/sys/include/sys/syscall.h +++ b/src/sys/include/sys/syscall.h @@ -58,6 +58,7 @@ #define SYS_dmsio 0x0D /* DMS I/O */ #define SYS_read 0x0E /* read a file descriptor */ #define SYS_close 0x0F /* close a file */ +#define SYS_lseek 0x10 /* seek to end of file */ typedef __ssize_t scret_t; typedef __ssize_t scarg_t; diff --git a/src/sys/os/os_filedes.c b/src/sys/os/os_filedes.c index ca56fc3..36748a6 100644 --- a/src/sys/os/os_filedes.c +++ b/src/sys/os/os_filedes.c @@ -359,6 +359,44 @@ read(int fd, void *buf, size_t count) return retval; } +off_t +lseek(int fd, off_t offset, int whence) +{ + struct filedesc *fdp; + struct proc *self = proc_self(); + struct vattr attr; + int error; + + if (fd < 0) { + return -EBADF; + } + + fdp = fd_get(self, fd); + if (fdp == NULL) { + return -EBADF; + } + + /* Could not get vnode attributes */ + error = vop_getattr(fdp->vp, &attr); + if (error < 0) { + return 0; + } + + switch (whence) { + case SEEK_SET: + fdp->off = offset; + break; + case SEEK_CUR: + fdp->off += offset; + break; + case SEEK_END: + fdp->off = attr.size; + break; + } + + return fdp->off; +} + /* * ARG0: Path * ARG1: Mode @@ -378,3 +416,18 @@ sys_open(struct syscall_args *scargs) return fd_open(pathbuf, mode); } + +/* + * ARG0: Fd + * ARG1: Offset + * ARG2: Whence + */ +scret_t +sys_lseek(struct syscall_args *scargs) +{ + int fd = SCARG(scargs, int, 0); + off_t off = SCARG(scargs, off_t, 1); + int whence = SCARG(scargs, int, 2); + + return lseek(fd, off, whence); +} diff --git a/src/sys/os/vfs_subr.c b/src/sys/os/vfs_subr.c index adfcffb..2ae18af 100644 --- a/src/sys/os/vfs_subr.c +++ b/src/sys/os/vfs_subr.c @@ -246,3 +246,23 @@ vop_create(struct vnode *vp, struct nameidata *ndp) args.ndp = ndp; return vops->create(&args); } + +int +vop_getattr(struct vnode *vp, struct vattr *res) +{ + struct vop *vops; + + if (vp == NULL || res == NULL) { + return -EINVAL; + } + + if ((vops = vp->vops) == NULL) { + return -EIO; + } + + if (vops->getattr == NULL) { + return -EIO; + } + + return vops->getattr(vp, res); +} |