summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-10-03 16:08:46 +0200
committerAnton Kling <anton@kling.gg>2024-10-03 16:09:12 +0200
commit372c633aa22d826bc515213ad4211791440f60f8 (patch)
treeb2de66c9bf612a0a149c65786335a6cebde37840 /kernel
parent226d861c9ebb7f09f95665d07d9ab5c6b7ed7d6f (diff)
libc: Add sendfile and queue
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cpu/syscall.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c
index 0dd2356..d31835d 100644
--- a/kernel/cpu/syscall.c
+++ b/kernel/cpu/syscall.c
@@ -567,6 +567,83 @@ int syscall_queue_wait(int fd, struct queue_entry *events, int num_events) {
return queue_wait(fd, events, num_events);
}
+u32 syscall_sendfile(int out_fd, int in_fd, off_t *offset, size_t count,
+ int *error_rc) {
+ int is_inf = (0 == count);
+
+ if (offset) {
+ if (!mmu_is_valid_userpointer(offset, sizeof(off_t))) {
+ return -EFAULT;
+ }
+ }
+ if (error_rc) {
+ if (!mmu_is_valid_userpointer(error_rc, sizeof(int))) {
+ return -EFAULT;
+ }
+ }
+
+ vfs_fd_t *in_fd_ptr = get_vfs_fd(in_fd, NULL);
+ if (!in_fd_ptr) {
+ return -EBADF;
+ }
+
+ vfs_fd_t *out_fd_ptr = get_vfs_fd(out_fd, NULL);
+ if (!out_fd_ptr) {
+ return -EBADF;
+ }
+
+ int real_rc = 0;
+
+ off_t read_offset = (offset) ? (*offset) : in_fd_ptr->offset;
+
+ for (; count > 0 || is_inf;) {
+ u8 buffer[8192];
+ int read_amount = min(sizeof(buffer), count);
+ if (is_inf) {
+ read_amount = sizeof(buffer);
+ }
+ int rc = vfs_pread(in_fd, buffer, read_amount, read_offset);
+ if (0 > rc) {
+ if (error_rc) {
+ *error_rc = rc;
+ }
+ return real_rc;
+ }
+
+ if (0 == rc) {
+ break;
+ }
+
+ int rc2 = vfs_pwrite(out_fd, buffer, rc, out_fd_ptr->offset);
+ if (0 > rc2) {
+ if (error_rc) {
+ *error_rc = rc2;
+ }
+ return real_rc;
+ }
+ real_rc += rc2;
+ if (!is_inf) {
+ count -= rc2;
+ }
+ out_fd_ptr->offset += rc2;
+
+ read_offset += rc2;
+ if (offset) {
+ *offset = read_offset;
+ } else {
+ in_fd_ptr->offset = read_offset;
+ }
+
+ if (rc < read_amount) {
+ break;
+ }
+ }
+ if (error_rc) {
+ *error_rc = 0;
+ }
+ return real_rc;
+}
+
int (*syscall_functions[])() = {
(void(*))syscall_open,
(void(*))syscall_read,
@@ -614,7 +691,7 @@ int (*syscall_functions[])() = {
(void(*))syscall_queue_create,
(void(*))syscall_queue_mod_entries,
(void(*))syscall_queue_wait,
-
+ (void(*))syscall_sendfile,
};
void int_syscall(reg_t *r);