Skip to content

Commit 0b24b47

Browse files
authored
[libc] Add the implementation of the fdopen function (#94186)
Fixes #93711 . This patch implements the ``fdopen`` function. Given that ``fdopen`` internally calls ``fcntl``, the implementation of ``fcntl`` has been moved to the ``__support/OSUtil``, where it serves as an internal public function.
1 parent 98b117e commit 0b24b47

File tree

18 files changed

+367
-77
lines changed

18 files changed

+367
-77
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ set(TARGET_LIBC_ENTRYPOINTS
201201
libc.src.stdio.snprintf
202202
libc.src.stdio.vsprintf
203203
libc.src.stdio.vsnprintf
204+
libc.src.stdio.fdopen
204205
#libc.src.stdio.sscanf
205206
#libc.src.stdio.scanf
206207
#libc.src.stdio.fscanf

libc/config/linux/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
209209
libc.src.stdio.sscanf
210210
libc.src.stdio.scanf
211211
libc.src.stdio.fscanf
212+
libc.src.stdio.fdopen
212213

213214
# sys/mman.h entrypoints
214215
libc.src.sys.mman.madvise

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ set(TARGET_LIBC_ENTRYPOINTS
214214
libc.src.stdio.scanf
215215
libc.src.stdio.fscanf
216216
libc.src.stdio.fileno
217+
libc.src.stdio.fdopen
217218

218219
# sys/epoll.h entrypoints
219220
libc.src.sys.epoll.epoll_create

libc/spec/posix.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,11 @@ def POSIX : StandardSpec<"POSIX"> {
13451345
RetValSpec<IntType>,
13461346
[ArgSpec<FILEPtr>]
13471347
>,
1348+
FunctionSpec<
1349+
"fdopen",
1350+
RetValSpec<FILEPtr>,
1351+
[ArgSpec<IntType>, ArgSpec<ConstCharPtr>]
1352+
>,
13481353
]
13491354
>;
13501355

libc/src/__support/File/linux/file.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88

99
#include "file.h"
1010

11-
#include "src/__support/File/file.h"
12-
1311
#include "src/__support/CPP/new.h"
12+
#include "src/__support/File/file.h"
1413
#include "src/__support/File/linux/lseekImpl.h"
14+
#include "src/__support/OSUtil/fcntl.h"
1515
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
1616
#include "src/errno/libc_errno.h" // For error macros
1717

@@ -119,6 +119,60 @@ ErrorOr<File *> openfile(const char *path, const char *mode) {
119119
return file;
120120
}
121121

122+
ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
123+
using ModeFlags = File::ModeFlags;
124+
ModeFlags modeflags = File::mode_flags(mode);
125+
if (modeflags == 0) {
126+
return Error(EINVAL);
127+
}
128+
129+
int fd_flags = internal::fcntl(fd, F_GETFL);
130+
if (fd_flags == -1) {
131+
return Error(EBADF);
132+
}
133+
134+
using OpenMode = File::OpenMode;
135+
if (((fd_flags & O_ACCMODE) == O_RDONLY &&
136+
!(modeflags & static_cast<ModeFlags>(OpenMode::READ))) ||
137+
((fd_flags & O_ACCMODE) == O_WRONLY &&
138+
!(modeflags & static_cast<ModeFlags>(OpenMode::WRITE)))) {
139+
return Error(EINVAL);
140+
}
141+
142+
bool do_seek = false;
143+
if ((modeflags & static_cast<ModeFlags>(OpenMode::APPEND)) &&
144+
!(fd_flags & O_APPEND)) {
145+
do_seek = true;
146+
if (internal::fcntl(fd, F_SETFL,
147+
reinterpret_cast<void *>(fd_flags | O_APPEND)) == -1) {
148+
return Error(EBADF);
149+
}
150+
}
151+
152+
uint8_t *buffer;
153+
{
154+
AllocChecker ac;
155+
buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE];
156+
if (!ac) {
157+
return Error(ENOMEM);
158+
}
159+
}
160+
AllocChecker ac;
161+
auto *file = new (ac)
162+
LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags);
163+
if (!ac) {
164+
return Error(ENOMEM);
165+
}
166+
if (do_seek) {
167+
auto result = file->seek(0, SEEK_END);
168+
if (!result.has_value()) {
169+
free(file);
170+
return Error(result.error());
171+
}
172+
}
173+
return file;
174+
}
175+
122176
int get_fileno(File *f) {
123177
auto *lf = reinterpret_cast<LinuxFile *>(f);
124178
return lf->get_fd();

libc/src/__support/File/linux/file.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,7 @@ class LinuxFile : public File {
2929
int get_fd() const { return fd; }
3030
};
3131

32+
// Create a File object and associate it with a fd.
33+
ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode);
34+
3235
} // namespace LIBC_NAMESPACE

libc/src/__support/OSUtil/fcntl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===-- Implementation header of internal fcntl function ------------------===//
2+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
//===----------------------------------------------------------------------===//
7+
8+
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H
9+
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H
10+
11+
namespace LIBC_NAMESPACE::internal {
12+
13+
int fcntl(int fd, int cmd, void *arg = nullptr);
14+
15+
} // namespace LIBC_NAMESPACE::internal
16+
17+
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H

libc/src/__support/OSUtil/linux/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ add_object_library(
88
linux_util
99
SRCS
1010
exit.cpp
11+
fcntl.cpp
1112
HDRS
1213
io.h
1314
syscall.h
1415
DEPENDS
1516
.${LIBC_TARGET_ARCHITECTURE}.linux_${LIBC_TARGET_ARCHITECTURE}_util
1617
libc.src.__support.common
1718
libc.src.__support.CPP.string_view
19+
libc.src.errno.errno
20+
libc.hdr.fcntl_macros
21+
libc.hdr.types.struct_flock
22+
libc.hdr.types.struct_flock64
23+
libc.hdr.types.struct_f_owner_ex
1824
)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//===-- Implementation of internal fcntl ----------------------------------===//
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 "src/__support/OSUtil/fcntl.h"
10+
11+
#include "hdr/fcntl_macros.h"
12+
#include "hdr/types/struct_f_owner_ex.h"
13+
#include "hdr/types/struct_flock.h"
14+
#include "hdr/types/struct_flock64.h"
15+
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
16+
#include "src/__support/common.h"
17+
#include "src/errno/libc_errno.h"
18+
19+
#include <stdarg.h>
20+
#include <sys/syscall.h> // For syscall numbers.
21+
22+
namespace LIBC_NAMESPACE::internal {
23+
24+
int fcntl(int fd, int cmd, void *arg) {
25+
switch (cmd) {
26+
case F_OFD_SETLKW: {
27+
struct flock *flk = reinterpret_cast<struct flock *>(arg);
28+
// convert the struct to a flock64
29+
struct flock64 flk64;
30+
flk64.l_type = flk->l_type;
31+
flk64.l_whence = flk->l_whence;
32+
flk64.l_start = flk->l_start;
33+
flk64.l_len = flk->l_len;
34+
flk64.l_pid = flk->l_pid;
35+
// create a syscall
36+
return LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
37+
}
38+
case F_OFD_GETLK:
39+
case F_OFD_SETLK: {
40+
struct flock *flk = reinterpret_cast<struct flock *>(arg);
41+
// convert the struct to a flock64
42+
struct flock64 flk64;
43+
flk64.l_type = flk->l_type;
44+
flk64.l_whence = flk->l_whence;
45+
flk64.l_start = flk->l_start;
46+
flk64.l_len = flk->l_len;
47+
flk64.l_pid = flk->l_pid;
48+
// create a syscall
49+
int retVal = LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
50+
// On failure, return
51+
if (retVal == -1)
52+
return -1;
53+
// Check for overflow, i.e. the offsets are not the same when cast
54+
// to off_t from off64_t.
55+
if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
56+
static_cast<off_t>(flk64.l_start) != flk64.l_start) {
57+
libc_errno = EOVERFLOW;
58+
return -1;
59+
}
60+
// Now copy back into flk, in case flk64 got modified
61+
flk->l_type = flk64.l_type;
62+
flk->l_whence = flk64.l_whence;
63+
flk->l_start = flk64.l_start;
64+
flk->l_len = flk64.l_len;
65+
flk->l_pid = flk64.l_pid;
66+
return retVal;
67+
}
68+
case F_GETOWN: {
69+
struct f_owner_ex fex;
70+
int retVal =
71+
LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, F_GETOWN_EX, &fex);
72+
if (retVal == -EINVAL)
73+
return LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd,
74+
reinterpret_cast<void *>(arg));
75+
if (static_cast<unsigned long>(retVal) <= -4096UL)
76+
return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid;
77+
78+
libc_errno = -retVal;
79+
return -1;
80+
}
81+
// The general case
82+
default: {
83+
int retVal = LIBC_NAMESPACE::syscall_impl<int>(
84+
SYS_fcntl, fd, cmd, reinterpret_cast<void *>(arg));
85+
if (retVal >= 0) {
86+
return retVal;
87+
}
88+
libc_errno = -retVal;
89+
return -1;
90+
}
91+
}
92+
}
93+
94+
} // namespace LIBC_NAMESPACE::internal

libc/src/fcntl/linux/CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,7 @@ add_entrypoint_object(
1818
../fcntl.h
1919
DEPENDS
2020
libc.include.fcntl
21-
libc.hdr.types.struct_flock
22-
libc.hdr.types.struct_flock64
23-
libc.hdr.types.struct_f_owner_ex
24-
libc.hdr.fcntl_macros
2521
libc.src.__support.OSUtil.osutil
26-
libc.src.errno.errno
2722
)
2823

2924
add_entrypoint_object(

0 commit comments

Comments
 (0)