1 //===--- Implementation of the Linux specialization of File ---------------===//
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
7 //===----------------------------------------------------------------------===//
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/macros/config.h"
19 #include "src/errno/libc_errno.h" // For error macros
21 #include "hdr/fcntl_macros.h" // For mode_t and other flags to the open syscall
22 #include <sys/stat.h> // For S_IS*, S_IF*, and S_IR* flags.
23 #include <sys/syscall.h> // For syscall numbers
25 namespace LIBC_NAMESPACE_DECL
{
27 FileIOResult
linux_file_write(File
*f
, const void *data
, size_t size
) {
28 auto *lf
= reinterpret_cast<LinuxFile
*>(f
);
30 LIBC_NAMESPACE::syscall_impl
<int>(SYS_write
, lf
->get_fd(), data
, size
);
37 FileIOResult
linux_file_read(File
*f
, void *buf
, size_t size
) {
38 auto *lf
= reinterpret_cast<LinuxFile
*>(f
);
40 LIBC_NAMESPACE::syscall_impl
<int>(SYS_read
, lf
->get_fd(), buf
, size
);
47 ErrorOr
<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();
55 int 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());
65 ErrorOr
<File
*> openfile(const char *path
, const char *mode
) {
66 using ModeFlags
= File::ModeFlags
;
67 auto modeflags
= File::mode_flags(mode
);
69 // return {nullptr, EINVAL};
73 if (modeflags
& ModeFlags(File::OpenMode::APPEND
)) {
74 open_flags
= O_CREAT
| O_APPEND
;
75 if (modeflags
& ModeFlags(File::OpenMode::PLUS
))
78 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
))
84 open_flags
|= O_WRONLY
;
86 if (modeflags
& ModeFlags(File::OpenMode::PLUS
))
89 open_flags
|= O_RDONLY
;
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
;
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
);
103 #error "open and openat syscalls not available."
112 buffer
= new (ac
) uint8_t[File::DEFAULT_BUFFER_SIZE
];
114 return Error(ENOMEM
);
117 auto *file
= new (ac
)
118 LinuxFile(fd
, buffer
, File::DEFAULT_BUFFER_SIZE
, _IOFBF
, true, modeflags
);
120 return Error(ENOMEM
);
124 ErrorOr
<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
);
131 int fd_flags
= internal::fcntl(fd
, F_GETFL
);
132 if (fd_flags
== -1) {
136 using OpenMode
= File::OpenMode
;
137 if (((fd_flags
& O_ACCMODE
) == O_RDONLY
&&
138 !(modeflags
& static_cast<ModeFlags
>(OpenMode::READ
))) ||
139 ((fd_flags
& O_ACCMODE
) == O_WRONLY
&&
140 !(modeflags
& static_cast<ModeFlags
>(OpenMode::WRITE
)))) {
141 return Error(EINVAL
);
144 bool do_seek
= false;
145 if ((modeflags
& static_cast<ModeFlags
>(OpenMode::APPEND
)) &&
146 !(fd_flags
& O_APPEND
)) {
148 if (internal::fcntl(fd
, F_SETFL
,
149 reinterpret_cast<void *>(fd_flags
| O_APPEND
)) == -1) {
157 buffer
= new (ac
) uint8_t[File::DEFAULT_BUFFER_SIZE
];
159 return Error(ENOMEM
);
163 auto *file
= new (ac
)
164 LinuxFile(fd
, buffer
, File::DEFAULT_BUFFER_SIZE
, _IOFBF
, true, modeflags
);
166 return Error(ENOMEM
);
169 auto result
= file
->seek(0, SEEK_END
);
170 if (!result
.has_value()) {
172 return Error(result
.error());
178 int get_fileno(File
*f
) {
179 auto *lf
= reinterpret_cast<LinuxFile
*>(f
);
183 } // namespace LIBC_NAMESPACE_DECL