1// See LICENSE for license details. 2 3#include "file.h" 4#include "atomic.h" 5#include "mmap.h" 6#include "frontend.h" 7#include "syscall.h" 8#include "pk.h" 9#include <string.h> 10#include <errno.h> 11 12#define MAX_FDS 128 13static file_t* fds[MAX_FDS]; 14#define MAX_FILES 128 15file_t files[MAX_FILES] = {[0 ... MAX_FILES-1] = {-1,0}}; 16 17void file_incref(file_t* f) 18{ 19 long prev = atomic_add(&f->refcnt, 1); 20 kassert(prev > 0); 21} 22 23void file_decref(file_t* f) 24{ 25 if (atomic_add(&f->refcnt, -1) == 2) 26 { 27 int kfd = f->kfd; 28 mb(); 29 atomic_set(&f->refcnt, 0); 30 31 frontend_syscall(SYS_close, kfd, 0, 0, 0, 0, 0, 0); 32 } 33} 34 35static file_t* file_get_free() 36{ 37 for (file_t* f = files; f < files + MAX_FILES; f++) 38 if (atomic_read(&f->refcnt) == 0 && atomic_cas(&f->refcnt, 0, 2) == 0) 39 return f; 40 return NULL; 41} 42 43int file_dup(file_t* f) 44{ 45 for (int i = 0; i < MAX_FDS; i++) 46 { 47 if (atomic_cas(&fds[i], 0, f) == 0) 48 { 49 file_incref(f); 50 return i; 51 } 52 } 53 return -1; 54} 55 56void file_init() 57{ 58 // create stdin, stdout, stderr and FDs 0-2 59 for (int i = 0; i < 3; i++) { 60 file_t* f = file_get_free(); 61 f->kfd = i; 62 file_dup(f); 63 } 64} 65 66file_t* file_get(int fd) 67{ 68 file_t* f; 69 if (fd < 0 || fd >= MAX_FDS || (f = atomic_read(&fds[fd])) == NULL) 70 return 0; 71 72 long old_cnt; 73 do { 74 old_cnt = atomic_read(&f->refcnt); 75 if (old_cnt == 0) 76 return 0; 77 } while (atomic_cas(&f->refcnt, old_cnt, old_cnt+1) != old_cnt); 78 79 return f; 80} 81 82file_t* file_open(const char* fn, int flags, int mode) 83{ 84 return file_openat(AT_FDCWD, fn, flags, mode); 85} 86 87file_t* file_openat(int dirfd, const char* fn, int flags, int mode) 88{ 89 file_t* f = file_get_free(); 90 if (f == NULL) 91 return ERR_PTR(-ENOMEM); 92 93 size_t fn_size = strlen(fn)+1; 94 long ret = frontend_syscall(SYS_openat, dirfd, va2pa(fn), fn_size, flags, mode, 0, 0); 95 if (ret >= 0) 96 { 97 f->kfd = ret; 98 return f; 99 } 100 else 101 { 102 file_decref(f); 103 return ERR_PTR(ret); 104 } 105} 106 107int fd_close(int fd) 108{ 109 file_t* f = file_get(fd); 110 if (!f) 111 return -1; 112 file_t* old = atomic_cas(&fds[fd], f, 0); 113 file_decref(f); 114 if (old != f) 115 return -1; 116 file_decref(f); 117 return 0; 118} 119 120ssize_t file_read(file_t* f, void* buf, size_t size) 121{ 122 populate_mapping(buf, size, PROT_WRITE); 123 return frontend_syscall(SYS_read, f->kfd, va2pa(buf), size, 0, 0, 0, 0); 124} 125 126ssize_t file_pread(file_t* f, void* buf, size_t size, off_t offset) 127{ 128 populate_mapping(buf, size, PROT_WRITE); 129 return frontend_syscall(SYS_pread, f->kfd, va2pa(buf), size, offset, 0, 0, 0); 130} 131 132ssize_t file_write(file_t* f, const void* buf, size_t size) 133{ 134 populate_mapping(buf, size, PROT_READ); 135 return frontend_syscall(SYS_write, f->kfd, va2pa(buf), size, 0, 0, 0, 0); 136} 137 138ssize_t file_pwrite(file_t* f, const void* buf, size_t size, off_t offset) 139{ 140 populate_mapping(buf, size, PROT_READ); 141 return frontend_syscall(SYS_pwrite, f->kfd, va2pa(buf), size, offset, 0, 0, 0); 142} 143 144int file_stat(file_t* f, struct stat* s) 145{ 146 struct frontend_stat buf; 147 long ret = frontend_syscall(SYS_fstat, f->kfd, va2pa(&buf), 0, 0, 0, 0, 0); 148 copy_stat(s, &buf); 149 return ret; 150} 151 152int file_truncate(file_t* f, off_t len) 153{ 154 return frontend_syscall(SYS_ftruncate, f->kfd, len, 0, 0, 0, 0, 0); 155} 156 157ssize_t file_lseek(file_t* f, size_t ptr, int dir) 158{ 159 return frontend_syscall(SYS_lseek, f->kfd, ptr, dir, 0, 0, 0, 0); 160} 161