diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm index 12bba1cc..c75e911a 100644 --- a/src/arch/x86_64/syscall.asm +++ b/src/arch/x86_64/syscall.asm @@ -7,6 +7,7 @@ extern syscall_arch_ctl extern syscall_gettid extern syscall_open extern syscall_read +extern syscall_lseek func_count equ 6 @@ -17,6 +18,7 @@ func_table: dq syscall_gettid dq syscall_open dq syscall_read + dq syscall_lseek section .text global asm_syscall_entry diff --git a/src/sys/syscalls/lseek.c b/src/sys/syscalls/lseek.c new file mode 100644 index 00000000..698b8998 --- /dev/null +++ b/src/sys/syscalls/lseek.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +syscallret syscall_lseek(int ifd, off_t offset, int whence){ + + syscallret retv; + retv.ret = -1; + + proc_t* proc = arch_getcls()->thread->proc; + + fd_t* fd = proc->fds + ifd; + + spinlock_acquire(&proc->fdlock); + + if(proc->fdcount <= ifd || fd->node == NULL || (fd->flags & FD_FLAGS_READ) == 0){ + spinlock_release(&proc->fdlock); + retv.errno = EBADF; + return retv; + } + + spinlock_acquire(&fd->lock); + spinlock_release(&proc->fdlock); + + int type = GETTYPE(fd->node->st.st_mode); + + if(type == TYPE_SOCKET || type == TYPE_FIFO){ + retv.errno = ESPIPE; + goto _ret; + } + + off_t newoffset = fd->offset; + size_t fsize = fd->node->st.st_size; + + switch(whence){ + case SEEK_SET: + if(offset < 0 || offset > fsize){ + retv.errno = EINVAL; + goto _ret; + } + newoffset = offset; + break; + case SEEK_CUR: + newoffset += offset; + if(newoffset < 0 || newoffset > fsize){ + retv.errno = EINVAL; + goto _ret; + } + + if(newoffset < offset){ + retv.errno = EOVERFLOW; + goto _ret; + } + break; + case SEEK_END: + newoffset = fsize; + break; + default: + retv.errno = EINVAL; + goto _ret; + } + + fd->offset = newoffset; + retv.errno = 0; + retv.ret = newoffset; + + _ret: + spinlock_release(&fd->lock); + return retv; + +}