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
23namespace LIBC_NAMESPACE {
24
25FileIOResult 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
35FileIOResult 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
45ErrorOr<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
53int 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
63ErrorOr<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
122int get_fileno(File *f) {
123 auto *lf = reinterpret_cast<LinuxFile *>(f);
124 return lf->get_fd();
125}
126
127} // namespace LIBC_NAMESPACE
128

source code of libc/src/__support/File/linux/file.cpp