diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -418,6 +418,7 @@ libc.src.stdio.clearerr libc.src.stdio.clearerr_unlocked libc.src.stdio.fclose + libc.src.stdio.fdopen libc.src.stdio.flockfile libc.src.stdio.feof libc.src.stdio.feof_unlocked diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -1131,6 +1131,12 @@ RetValSpec, [ArgSpec] >, + FunctionSpec< + "fdopen", + RetValSpec, + [ArgSpec, + ArgSpec] + >, FunctionSpec< "getc_unlocked", RetValSpec, diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h --- a/libc/src/__support/File/file.h +++ b/libc/src/__support/File/file.h @@ -302,6 +302,7 @@ // The implementaiton of this function is provided by the platfrom_file // library. ErrorOr openfile(const char *path, const char *mode); +ErrorOr openfile(int fd, const char *mode); // The platform_file library should implement it if it relevant for that // platform. diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp --- a/libc/src/__support/File/linux/file.cpp +++ b/libc/src/__support/File/linux/file.cpp @@ -161,6 +161,31 @@ return file; } +ErrorOr openfile(int fd, const char *mode) { + auto modeflags = File::mode_flags(mode); + if (modeflags == 0) { + // return {nullptr, EINVAL}; + return Error(EINVAL); + } + + if (fd < 0) + return Error(-fd); + + uint8_t *buffer; + { + AllocChecker ac; + buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE]; + if (!ac) + return Error(ENOMEM); + } + AllocChecker ac; + auto *file = new (ac) + LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags); + if (!ac) + return Error(ENOMEM); + return file; +} + int get_fileno(File *f) { auto *lf = reinterpret_cast(f); return lf->get_fd(); diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -38,6 +38,18 @@ libc.src.__support.File.platform_file ) +add_entrypoint_object( + fdopen + SRCS + fdopen.cpp + HDRS + fdopen.h + DEPENDS + libc.include.stdio + libc.src.__support.File.file + libc.src.__support.File.platform_file +) + add_entrypoint_object( fclose SRCS diff --git a/libc/src/stdio/fdopen.h b/libc/src/stdio/fdopen.h new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fdopen.h @@ -0,0 +1,21 @@ +//===-- Implementation header of fdopen --------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDIO_FDOPEN_H +#define LLVM_LIBC_SRC_STDIO_FDOPEN_H + +#include + +namespace __llvm_libc { + +::FILE *fdopen(int fd, const char *__restrict mode); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDIO_FDOPEN_H diff --git a/libc/src/stdio/fdopen.cpp b/libc/src/stdio/fdopen.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdio/fdopen.cpp @@ -0,0 +1,27 @@ +//===-- Implementation of fdopen +//-------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/fdopen.h" +#include "src/__support/File/file.h" + +#include "src/errno/libc_errno.h" +#include + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(::FILE *, fdopen, (int fd, const char *__restrict mode)) { + auto result = __llvm_libc::openfile(fd, mode); + if (!result.has_value()) { + libc_errno = result.error(); + return nullptr; + } + return reinterpret_cast<::FILE *>(result.value()); +} + +} // namespace __llvm_libc