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 @@ -102,6 +102,44 @@ } // anonymous namespace +ErrorOr allocatefile(int fd, File::ModeFlags modeflags) { + 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; +} + +ErrorOr openfile(int fd, const char *mode) { + if (fd < 0) + return Error(EBADF); + using ModeFlags = File::ModeFlags; + auto modeflags = File::mode_flags(mode); + if (modeflags == 0) { + // return {nullptr, EINVAL}; + return Error(EINVAL); + } + + if (modeflags & ModeFlags(File::OpenMode::APPEND)) { + auto cur_flags = __llvm_libc::syscall_impl(SYS_fcntl, fd, F_GETFL); + if (!(cur_flags & O_APPEND)) + __llvm_libc::syscall_impl(SYS_fcntl, fd, F_SETFL, + cur_flags | O_APPEND); + } + return allocatefile(fd, modeflags); +} + ErrorOr openfile(const char *path, const char *mode) { using ModeFlags = File::ModeFlags; auto modeflags = File::mode_flags(mode); @@ -143,22 +181,7 @@ #error "open and openat syscalls not available." #endif - 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; + return allocatefile(fd, modeflags); } int get_fileno(File *f) { 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