• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "file.h"
10 
11 #include "src/__support/File/file.h"
12 
13 #include "src/__support/CPP/new.h"
14 #include "src/__support/File/linux/lseekImpl.h"
15 #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
16 #include "src/errno/libc_errno.h"         // For error macros
17 
18 #include <fcntl.h> // For mode_t and other flags to the open syscall
19 #include <stdio.h>
20 #include <sys/stat.h>    // For S_IS*, S_IF*, and S_IR* flags.
21 #include <sys/syscall.h> // For syscall numbers
22 
23 namespace LIBC_NAMESPACE {
24 
linux_file_write(File * f,const void * data,size_t size)25 FileIOResult linux_file_write(File *f, const void *data, size_t size) {
26   auto *lf = reinterpret_cast<LinuxFile *>(f);
27   int ret =
28       LIBC_NAMESPACE::syscall_impl<int>(SYS_write, lf->get_fd(), data, size);
29   if (ret < 0) {
30     return {0, -ret};
31   }
32   return ret;
33 }
34 
linux_file_read(File * f,void * buf,size_t size)35 FileIOResult linux_file_read(File *f, void *buf, size_t size) {
36   auto *lf = reinterpret_cast<LinuxFile *>(f);
37   int ret =
38       LIBC_NAMESPACE::syscall_impl<int>(SYS_read, lf->get_fd(), buf, size);
39   if (ret < 0) {
40     return {0, -ret};
41   }
42   return ret;
43 }
44 
linux_file_seek(File * f,long offset,int whence)45 ErrorOr<long> linux_file_seek(File *f, long offset, int whence) {
46   auto *lf = reinterpret_cast<LinuxFile *>(f);
47   auto result = internal::lseekimpl(lf->get_fd(), offset, whence);
48   if (!result.has_value())
49     return result.error();
50   return result.value();
51 }
52 
linux_file_close(File * f)53 int linux_file_close(File *f) {
54   auto *lf = reinterpret_cast<LinuxFile *>(f);
55   int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, lf->get_fd());
56   if (ret < 0) {
57     return -ret;
58   }
59   delete lf;
60   return 0;
61 }
62 
openfile(const char * path,const char * mode)63 ErrorOr<File *> openfile(const char *path, const char *mode) {
64   using ModeFlags = File::ModeFlags;
65   auto modeflags = File::mode_flags(mode);
66   if (modeflags == 0) {
67     // return {nullptr, EINVAL};
68     return Error(EINVAL);
69   }
70   long open_flags = 0;
71   if (modeflags & ModeFlags(File::OpenMode::APPEND)) {
72     open_flags = O_CREAT | O_APPEND;
73     if (modeflags & ModeFlags(File::OpenMode::PLUS))
74       open_flags |= O_RDWR;
75     else
76       open_flags |= O_WRONLY;
77   } else if (modeflags & ModeFlags(File::OpenMode::WRITE)) {
78     open_flags = O_CREAT | O_TRUNC;
79     if (modeflags & ModeFlags(File::OpenMode::PLUS))
80       open_flags |= O_RDWR;
81     else
82       open_flags |= O_WRONLY;
83   } else {
84     if (modeflags & ModeFlags(File::OpenMode::PLUS))
85       open_flags |= O_RDWR;
86     else
87       open_flags |= O_RDONLY;
88   }
89 
90   // File created will have 0666 permissions.
91   constexpr long OPEN_MODE =
92       S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
93 
94 #ifdef SYS_open
95   int fd =
96       LIBC_NAMESPACE::syscall_impl<int>(SYS_open, path, open_flags, OPEN_MODE);
97 #elif defined(SYS_openat)
98   int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, path,
99                                              open_flags, OPEN_MODE);
100 #else
101 #error "open and openat syscalls not available."
102 #endif
103 
104   if (fd < 0)
105     return Error(-fd);
106 
107   uint8_t *buffer;
108   {
109     AllocChecker ac;
110     buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE];
111     if (!ac)
112       return Error(ENOMEM);
113   }
114   AllocChecker ac;
115   auto *file = new (ac)
116       LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags);
117   if (!ac)
118     return Error(ENOMEM);
119   return file;
120 }
121 
get_fileno(File * f)122 int get_fileno(File *f) {
123   auto *lf = reinterpret_cast<LinuxFile *>(f);
124   return lf->get_fd();
125 }
126 
127 } // namespace LIBC_NAMESPACE
128