brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.1 KiB · 4594dad Raw
186 lines · cpp
1//===--- Implementation of the Linux specialization of File ---------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "file.h"10 11#include "hdr/stdio_macros.h"12#include "hdr/types/off_t.h"13#include "src/__support/CPP/new.h"14#include "src/__support/File/file.h"15#include "src/__support/File/linux/lseekImpl.h"16#include "src/__support/OSUtil/fcntl.h"17#include "src/__support/OSUtil/syscall.h" // For internal syscall function.18#include "src/__support/libc_errno.h"     // For error macros19#include "src/__support/macros/config.h"20 21#include "hdr/fcntl_macros.h" // For mode_t and other flags to the open syscall22#include <sys/stat.h>         // For S_IS*, S_IF*, and S_IR* flags.23#include <sys/syscall.h>      // For syscall numbers24 25namespace LIBC_NAMESPACE_DECL {26 27FileIOResult linux_file_write(File *f, const void *data, size_t size) {28  auto *lf = reinterpret_cast<LinuxFile *>(f);29  int ret =30      LIBC_NAMESPACE::syscall_impl<int>(SYS_write, lf->get_fd(), data, size);31  if (ret < 0) {32    return {0, -ret};33  }34  return ret;35}36 37FileIOResult linux_file_read(File *f, void *buf, size_t size) {38  auto *lf = reinterpret_cast<LinuxFile *>(f);39  int ret =40      LIBC_NAMESPACE::syscall_impl<int>(SYS_read, lf->get_fd(), buf, size);41  if (ret < 0) {42    return {0, -ret};43  }44  return ret;45}46 47ErrorOr<off_t> linux_file_seek(File *f, off_t offset, int whence) {48  auto *lf = reinterpret_cast<LinuxFile *>(f);49  auto result = internal::lseekimpl(lf->get_fd(), offset, whence);50  if (!result.has_value())51    return result.error();52  return result.value();53}54 55int linux_file_close(File *f) {56  auto *lf = reinterpret_cast<LinuxFile *>(f);57  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, lf->get_fd());58  if (ret < 0) {59    return -ret;60  }61  delete lf;62  return 0;63}64 65ErrorOr<File *> openfile(const char *path, const char *mode) {66  using ModeFlags = File::ModeFlags;67  auto modeflags = File::mode_flags(mode);68  if (modeflags == 0) {69    // return {nullptr, EINVAL};70    return Error(EINVAL);71  }72  long open_flags = 0;73  if (modeflags & ModeFlags(File::OpenMode::APPEND)) {74    open_flags = O_CREAT | O_APPEND;75    if (modeflags & ModeFlags(File::OpenMode::PLUS))76      open_flags |= O_RDWR;77    else78      open_flags |= O_WRONLY;79  } else if (modeflags & ModeFlags(File::OpenMode::WRITE)) {80    open_flags = O_CREAT | O_TRUNC;81    if (modeflags & ModeFlags(File::OpenMode::PLUS))82      open_flags |= O_RDWR;83    else84      open_flags |= O_WRONLY;85  } else {86    if (modeflags & ModeFlags(File::OpenMode::PLUS))87      open_flags |= O_RDWR;88    else89      open_flags |= O_RDONLY;90  }91 92  // File created will have 0666 permissions.93  constexpr long OPEN_MODE =94      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;95 96#ifdef SYS_open97  int fd =98      LIBC_NAMESPACE::syscall_impl<int>(SYS_open, path, open_flags, OPEN_MODE);99#elif defined(SYS_openat)100  int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, path,101                                             open_flags, OPEN_MODE);102#else103#error "open and openat syscalls not available."104#endif105 106  if (fd < 0)107    return Error(-fd);108 109  uint8_t *buffer;110  {111    AllocChecker ac;112    buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE];113    if (!ac)114      return Error(ENOMEM);115  }116  AllocChecker ac;117  auto *file = new (ac)118      LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags);119  if (!ac)120    return Error(ENOMEM);121  return file;122}123 124ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {125  using ModeFlags = File::ModeFlags;126  ModeFlags modeflags = File::mode_flags(mode);127  if (modeflags == 0) {128    return Error(EINVAL);129  }130 131  auto result = internal::fcntl(fd, F_GETFL);132  if (!result.has_value()) {133    return Error(EBADF);134  }135  int fd_flags = result.value();136 137  using OpenMode = File::OpenMode;138  if (((fd_flags & O_ACCMODE) == O_RDONLY &&139       !(modeflags & static_cast<ModeFlags>(OpenMode::READ))) ||140      ((fd_flags & O_ACCMODE) == O_WRONLY &&141       !(modeflags & static_cast<ModeFlags>(OpenMode::WRITE)))) {142    return Error(EINVAL);143  }144 145  bool do_seek = false;146  if ((modeflags & static_cast<ModeFlags>(OpenMode::APPEND)) &&147      !(fd_flags & O_APPEND)) {148    do_seek = true;149    if (!internal::fcntl(fd, F_SETFL,150                         reinterpret_cast<void *>(fd_flags | O_APPEND))151             .has_value()) {152      return Error(EBADF);153    }154  }155 156  uint8_t *buffer;157  {158    AllocChecker ac;159    buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE];160    if (!ac) {161      return Error(ENOMEM);162    }163  }164  AllocChecker ac;165  auto *file = new (ac)166      LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags);167  if (!ac) {168    return Error(ENOMEM);169  }170  if (do_seek) {171    auto result = file->seek(0, SEEK_END);172    if (!result.has_value()) {173      free(file);174      return Error(result.error());175    }176  }177  return file;178}179 180int get_fileno(File *f) {181  auto *lf = reinterpret_cast<LinuxFile *>(f);182  return lf->get_fd();183}184 185} // namespace LIBC_NAMESPACE_DECL186