1/* 2 * Copyright 2018, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdint.h> 14#include <string.h> 15#include <fcntl.h> 16#include <errno.h> 17#include <sys/uio.h> 18#include <utils/util.h> 19#include <muslcsys/vsyscall.h> 20#include "fsclient.h" 21 22static void *ext_buf; 23static int (*ext_open)(const char *name, int flags); 24static ssize_t (*ext_read)(int fd, size_t size); 25static int64_t (*ext_seek)(int fd, int64_t offset, int whence); 26static int (*ext_close)(int fd); 27 28static long fileserver_open(va_list ap) { 29 const char *pathname = va_arg(ap, const char *); 30 int flags = va_arg(ap, int); 31 return ext_open(pathname, flags); 32} 33 34static long fileserver_openat(va_list ap) { 35 int dirfd = va_arg(ap, int); 36 const char *pathname = va_arg(ap, const char *); 37 int flags = va_arg(ap, int); 38 39 if (dirfd != AT_FDCWD) { 40 ZF_LOGE("Openat only supports relative path to the current working directory\n"); 41 return -EINVAL; 42 } 43 return ext_open(pathname, flags); 44} 45 46static long fileserver_close(va_list ap) { 47 int fd = va_arg(ap, int); 48 return ext_close(fd); 49} 50 51static long fileserver_read(va_list ap) { 52 int fd = va_arg(ap, int); 53 void *buf = va_arg(ap, void*); 54 size_t count = va_arg(ap, size_t); 55 ssize_t total = 0; 56 size_t remain = count; 57 while (total < count) { 58 ssize_t result = ext_read(fd, remain); 59 if (result <= 0) { 60 return total; 61 } 62 memcpy(buf + total, ext_buf, result); 63 total += result; 64 remain -= result; 65 } 66 return total; 67} 68 69static long fileserver_readv(va_list ap) { 70 int fd = va_arg(ap, int); 71 struct iovec *iov = va_arg(ap, struct iovec*); 72 int iovcnt = va_arg(ap, int); 73 ssize_t total = 0; 74 int i; 75 for (i = 0; i < iovcnt; i++) { 76 long iov_offset = 0; 77 while (iov_offset < iov[i].iov_len) { 78 long read = ext_read(fd, iov[i].iov_len - iov_offset); 79 if (read <= 0) { 80 return total; 81 } 82 memcpy(iov[i].iov_base + iov_offset, ext_buf, read); 83 iov_offset += read; 84 total += read; 85 } 86 } 87 return total; 88} 89 90static long fileserver_lseek(va_list ap) { 91 int fd = va_arg(ap, int); 92 off_t offset = va_arg(ap, off_t); 93 int whence = va_arg(ap, int); 94 95 return ext_seek(fd, offset, whence); 96} 97 98static long fileserver_llseek(va_list ap) { 99 int fd = va_arg(ap, int); 100 uint32_t offset_high = va_arg(ap, uint32_t); 101 uint32_t offset_low = va_arg(ap, uint32_t); 102 off_t *result = va_arg(ap, off_t*); 103 int whence = va_arg(ap, int); 104 105 *result = ext_seek(fd, (((uint64_t)offset_high) << 32) | offset_low, whence); 106 return 0; 107} 108 109void install_fileserver(file_server_interface_t fs_interface) { 110 ext_buf = fs_interface.ext_buf; 111 ext_open = fs_interface.ext_open; 112 ext_read = fs_interface.ext_read; 113 ext_seek = fs_interface.ext_seek; 114 ext_close = fs_interface.ext_close; 115#ifdef __NR_open 116 muslcsys_install_syscall(__NR_open, fileserver_open); 117#endif 118#ifdef __NR_openat 119 muslcsys_install_syscall(__NR_openat, fileserver_openat); 120#endif 121 muslcsys_install_syscall(__NR_close, fileserver_close); 122 muslcsys_install_syscall(__NR_read, fileserver_read); 123 muslcsys_install_syscall(__NR_readv, fileserver_readv); 124 muslcsys_install_syscall(__NR_lseek, fileserver_lseek); 125#ifdef __NR__llseek 126 muslcsys_install_syscall(__NR__llseek, fileserver_llseek); 127#endif 128} 129