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 | |
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, ts: lf->get_fd(), ts: data, ts: size); |
29 | if (ret < 0) { |
30 | return {0, -ret}; |
31 | } |
32 | return ret; |
33 | } |
34 | |
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, ts: lf->get_fd(), ts: buf, ts: size); |
39 | if (ret < 0) { |
40 | return {0, -ret}; |
41 | } |
42 | return ret; |
43 | } |
44 | |
45 | ErrorOr<long> linux_file_seek(File *f, long offset, int whence) { |
46 | auto *lf = reinterpret_cast<LinuxFile *>(f); |
47 | auto result = internal::lseekimpl(fd: lf->get_fd(), offset, whence); |
48 | if (!result.has_value()) |
49 | return result.error(); |
50 | return result.value(); |
51 | } |
52 | |
53 | int linux_file_close(File *f) { |
54 | auto *lf = reinterpret_cast<LinuxFile *>(f); |
55 | int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, ts: lf->get_fd()); |
56 | if (ret < 0) { |
57 | return -ret; |
58 | } |
59 | delete lf; |
60 | return 0; |
61 | } |
62 | |
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, ts: path, ts: open_flags, ts: 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 | |
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 | |