1df4814d4SSiva Chandra Reddy //===--- Linux specialization of the File data structure ------------------===// 2df4814d4SSiva Chandra Reddy // 3df4814d4SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4df4814d4SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information. 5df4814d4SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6df4814d4SSiva Chandra Reddy // 7df4814d4SSiva Chandra Reddy //===----------------------------------------------------------------------===// 8df4814d4SSiva Chandra Reddy 9df4814d4SSiva Chandra Reddy #include "file.h" 10df4814d4SSiva Chandra Reddy 11df4814d4SSiva Chandra Reddy #include "src/__support/OSUtil/syscall.h" // For internal syscall function. 12df4814d4SSiva Chandra Reddy 13df4814d4SSiva Chandra Reddy #include <errno.h> 14df4814d4SSiva Chandra Reddy #include <fcntl.h> // For mode_t and other flags to the open syscall 15df4814d4SSiva Chandra Reddy #include <stdlib.h> // For malloc 16df4814d4SSiva Chandra Reddy #include <sys/syscall.h> // For syscall numbers 17df4814d4SSiva Chandra Reddy 18df4814d4SSiva Chandra Reddy namespace __llvm_libc { 19df4814d4SSiva Chandra Reddy 20df4814d4SSiva Chandra Reddy namespace { 21df4814d4SSiva Chandra Reddy 22df4814d4SSiva Chandra Reddy size_t write_func(File *, const void *, size_t); 23df4814d4SSiva Chandra Reddy size_t read_func(File *, void *, size_t); 24df4814d4SSiva Chandra Reddy int seek_func(File *, long, int); 25df4814d4SSiva Chandra Reddy int close_func(File *); 26df4814d4SSiva Chandra Reddy int flush_func(File *); 27df4814d4SSiva Chandra Reddy 28df4814d4SSiva Chandra Reddy } // anonymous namespace 29df4814d4SSiva Chandra Reddy 30df4814d4SSiva Chandra Reddy class LinuxFile : public File { 31df4814d4SSiva Chandra Reddy int fd; 32df4814d4SSiva Chandra Reddy 33df4814d4SSiva Chandra Reddy public: 34df4814d4SSiva Chandra Reddy constexpr LinuxFile(int file_descriptor, void *buffer, size_t buffer_size, 35df4814d4SSiva Chandra Reddy int buffer_mode, bool owned, File::ModeFlags modeflags) 36df4814d4SSiva Chandra Reddy : File(&write_func, &read_func, &seek_func, &close_func, flush_func, 37df4814d4SSiva Chandra Reddy buffer, buffer_size, buffer_mode, owned, modeflags), 38df4814d4SSiva Chandra Reddy fd(file_descriptor) {} 39df4814d4SSiva Chandra Reddy 40df4814d4SSiva Chandra Reddy static void init(LinuxFile *f, int file_descriptor, void *buffer, 41df4814d4SSiva Chandra Reddy size_t buffer_size, int buffer_mode, bool owned, 42df4814d4SSiva Chandra Reddy File::ModeFlags modeflags) { 43df4814d4SSiva Chandra Reddy File::init(f, &write_func, &read_func, &seek_func, &close_func, &flush_func, 44df4814d4SSiva Chandra Reddy buffer, buffer_size, buffer_mode, owned, modeflags); 45df4814d4SSiva Chandra Reddy f->fd = file_descriptor; 46df4814d4SSiva Chandra Reddy } 47df4814d4SSiva Chandra Reddy 48df4814d4SSiva Chandra Reddy int get_fd() const { return fd; } 49df4814d4SSiva Chandra Reddy }; 50df4814d4SSiva Chandra Reddy 51df4814d4SSiva Chandra Reddy namespace { 52df4814d4SSiva Chandra Reddy 53df4814d4SSiva Chandra Reddy size_t write_func(File *f, const void *data, size_t size) { 54df4814d4SSiva Chandra Reddy auto *lf = reinterpret_cast<LinuxFile *>(f); 55df4814d4SSiva Chandra Reddy long ret = __llvm_libc::syscall(SYS_write, lf->get_fd(), data, size); 56df4814d4SSiva Chandra Reddy if (ret < 0) { 57df4814d4SSiva Chandra Reddy errno = -ret; 58df4814d4SSiva Chandra Reddy return 0; 59df4814d4SSiva Chandra Reddy } 60df4814d4SSiva Chandra Reddy return ret; 61df4814d4SSiva Chandra Reddy } 62df4814d4SSiva Chandra Reddy 63df4814d4SSiva Chandra Reddy size_t read_func(File *f, void *buf, size_t size) { 64df4814d4SSiva Chandra Reddy auto *lf = reinterpret_cast<LinuxFile *>(f); 65df4814d4SSiva Chandra Reddy long ret = __llvm_libc::syscall(SYS_read, lf->get_fd(), buf, size); 66df4814d4SSiva Chandra Reddy if (ret < 0) { 67df4814d4SSiva Chandra Reddy errno = -ret; 68df4814d4SSiva Chandra Reddy return 0; 69df4814d4SSiva Chandra Reddy } 70df4814d4SSiva Chandra Reddy return ret; 71df4814d4SSiva Chandra Reddy } 72df4814d4SSiva Chandra Reddy 73df4814d4SSiva Chandra Reddy int seek_func(File *f, long offset, int whence) { 74df4814d4SSiva Chandra Reddy auto *lf = reinterpret_cast<LinuxFile *>(f); 75df4814d4SSiva Chandra Reddy #ifdef SYS_lseek 76df4814d4SSiva Chandra Reddy long ret = __llvm_libc::syscall(SYS_lseek, lf->get_fd(), offset, whence); 77df4814d4SSiva Chandra Reddy #elif defined(SYS__llseek) 78df4814d4SSiva Chandra Reddy long result; 79df4814d4SSiva Chandra Reddy long ret = __llvm_libc::syscall(SYS__lseek, lf->get_fd(), offset >> 32, 80df4814d4SSiva Chandra Reddy offset, &result, whence); 81df4814d4SSiva Chandra Reddy #else 82df4814d4SSiva Chandra Reddy #error "lseek and _llseek syscalls not available to perform a seek operation." 83df4814d4SSiva Chandra Reddy #endif 84df4814d4SSiva Chandra Reddy 85df4814d4SSiva Chandra Reddy if (ret < 0) { 86df4814d4SSiva Chandra Reddy errno = -ret; 87df4814d4SSiva Chandra Reddy return -1; 88df4814d4SSiva Chandra Reddy } 89df4814d4SSiva Chandra Reddy return 0; 90df4814d4SSiva Chandra Reddy } 91df4814d4SSiva Chandra Reddy 92df4814d4SSiva Chandra Reddy int close_func(File *f) { 93df4814d4SSiva Chandra Reddy auto *lf = reinterpret_cast<LinuxFile *>(f); 94df4814d4SSiva Chandra Reddy long ret = __llvm_libc::syscall(SYS_close, lf->get_fd()); 95df4814d4SSiva Chandra Reddy if (ret < 0) { 96df4814d4SSiva Chandra Reddy errno = -ret; 97df4814d4SSiva Chandra Reddy return -1; 98df4814d4SSiva Chandra Reddy } 99df4814d4SSiva Chandra Reddy return 0; 100df4814d4SSiva Chandra Reddy } 101df4814d4SSiva Chandra Reddy 102df4814d4SSiva Chandra Reddy int flush_func(File *f) { 103df4814d4SSiva Chandra Reddy auto *lf = reinterpret_cast<LinuxFile *>(f); 104df4814d4SSiva Chandra Reddy long ret = __llvm_libc::syscall(SYS_fsync, lf->get_fd()); 105df4814d4SSiva Chandra Reddy if (ret < 0) { 106df4814d4SSiva Chandra Reddy errno = -ret; 107df4814d4SSiva Chandra Reddy return -1; 108df4814d4SSiva Chandra Reddy } 109df4814d4SSiva Chandra Reddy return 0; 110df4814d4SSiva Chandra Reddy } 111df4814d4SSiva Chandra Reddy 112df4814d4SSiva Chandra Reddy } // anonymous namespace 113df4814d4SSiva Chandra Reddy 114df4814d4SSiva Chandra Reddy File *openfile(const char *path, const char *mode) { 115df4814d4SSiva Chandra Reddy using ModeFlags = File::ModeFlags; 116df4814d4SSiva Chandra Reddy auto modeflags = File::mode_flags(mode); 117df4814d4SSiva Chandra Reddy if (modeflags == 0) { 118df4814d4SSiva Chandra Reddy errno = EINVAL; 119df4814d4SSiva Chandra Reddy return nullptr; 120df4814d4SSiva Chandra Reddy } 121df4814d4SSiva Chandra Reddy long open_flags = 0; 122df4814d4SSiva Chandra Reddy if (modeflags & ModeFlags(File::OpenMode::APPEND)) { 123df4814d4SSiva Chandra Reddy open_flags = O_CREAT | O_APPEND; 124df4814d4SSiva Chandra Reddy if (modeflags & ModeFlags(File::OpenMode::PLUS)) 125df4814d4SSiva Chandra Reddy open_flags |= O_RDWR; 126df4814d4SSiva Chandra Reddy else 127df4814d4SSiva Chandra Reddy open_flags |= O_WRONLY; 128df4814d4SSiva Chandra Reddy } else if (modeflags & ModeFlags(File::OpenMode::WRITE)) { 129df4814d4SSiva Chandra Reddy open_flags = O_CREAT | O_TRUNC; 130df4814d4SSiva Chandra Reddy if (modeflags & ModeFlags(File::OpenMode::PLUS)) 131df4814d4SSiva Chandra Reddy open_flags |= O_RDWR; 132df4814d4SSiva Chandra Reddy else 133df4814d4SSiva Chandra Reddy open_flags |= O_WRONLY; 134df4814d4SSiva Chandra Reddy } else { 135df4814d4SSiva Chandra Reddy if (modeflags & ModeFlags(File::OpenMode::PLUS)) 136df4814d4SSiva Chandra Reddy open_flags |= O_RDWR; 137df4814d4SSiva Chandra Reddy else 138df4814d4SSiva Chandra Reddy open_flags |= O_RDONLY; 139df4814d4SSiva Chandra Reddy } 140df4814d4SSiva Chandra Reddy 141df4814d4SSiva Chandra Reddy // File created will have 0666 permissions. 142df4814d4SSiva Chandra Reddy constexpr long OPEN_MODE = 143df4814d4SSiva Chandra Reddy S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 144df4814d4SSiva Chandra Reddy 145df4814d4SSiva Chandra Reddy #ifdef SYS_open 146df4814d4SSiva Chandra Reddy int fd = __llvm_libc::syscall(SYS_open, path, open_flags, OPEN_MODE); 147df4814d4SSiva Chandra Reddy #elif defined(SYS_openat) 148df4814d4SSiva Chandra Reddy int fd = 149df4814d4SSiva Chandra Reddy __llvm_libc::syscall(SYS_openat, AT_FDCWD, path, open_flags, OPEN_MODE); 150df4814d4SSiva Chandra Reddy #else 151df4814d4SSiva Chandra Reddy #error "SYS_open and SYS_openat syscalls not available to perform a file open." 152df4814d4SSiva Chandra Reddy #endif 153df4814d4SSiva Chandra Reddy 154df4814d4SSiva Chandra Reddy if (fd < 0) { 155df4814d4SSiva Chandra Reddy errno = -fd; 156df4814d4SSiva Chandra Reddy return nullptr; 157df4814d4SSiva Chandra Reddy } 158df4814d4SSiva Chandra Reddy 159df4814d4SSiva Chandra Reddy void *buffer = malloc(File::DEFAULT_BUFFER_SIZE); 160df4814d4SSiva Chandra Reddy auto *file = reinterpret_cast<LinuxFile *>(malloc(sizeof(LinuxFile))); 161df4814d4SSiva Chandra Reddy LinuxFile::init( 162df4814d4SSiva Chandra Reddy file, fd, buffer, File::DEFAULT_BUFFER_SIZE, 163df4814d4SSiva Chandra Reddy 0, // TODO: Set the correct buffer mode when buffer mode is available. 164df4814d4SSiva Chandra Reddy true, modeflags); 165df4814d4SSiva Chandra Reddy return file; 166df4814d4SSiva Chandra Reddy } 167df4814d4SSiva Chandra Reddy 168*9b8ca3c1SSiva Chandra Reddy // TODO: Use the appropriate buffering modes for the standard streams below 169*9b8ca3c1SSiva Chandra Reddy // the different buffering modes are available. 170*9b8ca3c1SSiva Chandra Reddy constexpr size_t STDOUT_BUFFER_SIZE = 1024; 171*9b8ca3c1SSiva Chandra Reddy char stdout_buffer[STDOUT_BUFFER_SIZE]; 172*9b8ca3c1SSiva Chandra Reddy static LinuxFile StdOut(1, stdout_buffer, STDOUT_BUFFER_SIZE, 0, false, 173*9b8ca3c1SSiva Chandra Reddy File::ModeFlags(File::OpenMode::APPEND)); 174*9b8ca3c1SSiva Chandra Reddy File *stdout = &StdOut; 175*9b8ca3c1SSiva Chandra Reddy 176*9b8ca3c1SSiva Chandra Reddy constexpr size_t STDERR_BUFFER_SIZE = 1024; 177*9b8ca3c1SSiva Chandra Reddy char stderr_buffer[STDERR_BUFFER_SIZE]; 178*9b8ca3c1SSiva Chandra Reddy static LinuxFile StdErr(2, stderr_buffer, STDERR_BUFFER_SIZE, 0, false, 179*9b8ca3c1SSiva Chandra Reddy File::ModeFlags(File::OpenMode::APPEND)); 180*9b8ca3c1SSiva Chandra Reddy File *stderr = &StdErr; 181*9b8ca3c1SSiva Chandra Reddy 182df4814d4SSiva Chandra Reddy } // namespace __llvm_libc 183