aboutsummaryrefslogtreecommitdiff
path: root/libc/src
diff options
context:
space:
mode:
authorXu Zhang <simonzgx@gmail.com>2024-06-15 07:17:44 +0800
committerGitHub <noreply@github.com>2024-06-14 16:17:44 -0700
commit0b24b4706982907799c838d80e06b3aa08420549 (patch)
tree7943efb95051d5f516004ad1687883e4ab737909 /libc/src
parent98b117e4355d2ba7b672014aafc41b3f646fc72c (diff)
downloadllvm-0b24b4706982907799c838d80e06b3aa08420549.zip
llvm-0b24b4706982907799c838d80e06b3aa08420549.tar.gz
llvm-0b24b4706982907799c838d80e06b3aa08420549.tar.bz2
[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.
Diffstat (limited to 'libc/src')
-rw-r--r--libc/src/__support/File/linux/file.cpp58
-rw-r--r--libc/src/__support/File/linux/file.h3
-rw-r--r--libc/src/__support/OSUtil/fcntl.h17
-rw-r--r--libc/src/__support/OSUtil/linux/CMakeLists.txt6
-rw-r--r--libc/src/__support/OSUtil/linux/fcntl.cpp94
-rw-r--r--libc/src/fcntl/linux/CMakeLists.txt5
-rw-r--r--libc/src/fcntl/linux/fcntl.cpp74
-rw-r--r--libc/src/stdio/CMakeLists.txt7
-rw-r--r--libc/src/stdio/fdopen.h20
-rw-r--r--libc/src/stdio/linux/CMakeLists.txt12
-rw-r--r--libc/src/stdio/linux/fdopen.cpp25
11 files changed, 244 insertions, 77 deletions
diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index b84da64..00ff938 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -8,10 +8,10 @@
#include "file.h"
-#include "src/__support/File/file.h"
-
#include "src/__support/CPP/new.h"
+#include "src/__support/File/file.h"
#include "src/__support/File/linux/lseekImpl.h"
+#include "src/__support/OSUtil/fcntl.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/errno/libc_errno.h" // For error macros
@@ -119,6 +119,60 @@ ErrorOr<File *> openfile(const char *path, const char *mode) {
return file;
}
+ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
+ using ModeFlags = File::ModeFlags;
+ ModeFlags modeflags = File::mode_flags(mode);
+ if (modeflags == 0) {
+ return Error(EINVAL);
+ }
+
+ int fd_flags = internal::fcntl(fd, F_GETFL);
+ if (fd_flags == -1) {
+ return Error(EBADF);
+ }
+
+ using OpenMode = File::OpenMode;
+ if (((fd_flags & O_ACCMODE) == O_RDONLY &&
+ !(modeflags & static_cast<ModeFlags>(OpenMode::READ))) ||
+ ((fd_flags & O_ACCMODE) == O_WRONLY &&
+ !(modeflags & static_cast<ModeFlags>(OpenMode::WRITE)))) {
+ return Error(EINVAL);
+ }
+
+ bool do_seek = false;
+ if ((modeflags & static_cast<ModeFlags>(OpenMode::APPEND)) &&
+ !(fd_flags & O_APPEND)) {
+ do_seek = true;
+ if (internal::fcntl(fd, F_SETFL,
+ reinterpret_cast<void *>(fd_flags | O_APPEND)) == -1) {
+ return Error(EBADF);
+ }
+ }
+
+ 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);
+ }
+ if (do_seek) {
+ auto result = file->seek(0, SEEK_END);
+ if (!result.has_value()) {
+ free(file);
+ return Error(result.error());
+ }
+ }
+ return file;
+}
+
int get_fileno(File *f) {
auto *lf = reinterpret_cast<LinuxFile *>(f);
return lf->get_fd();
diff --git a/libc/src/__support/File/linux/file.h b/libc/src/__support/File/linux/file.h
index 24e71b1..7d3770e 100644
--- a/libc/src/__support/File/linux/file.h
+++ b/libc/src/__support/File/linux/file.h
@@ -29,4 +29,7 @@ public:
int get_fd() const { return fd; }
};
+// Create a File object and associate it with a fd.
+ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode);
+
} // namespace LIBC_NAMESPACE
diff --git a/libc/src/__support/OSUtil/fcntl.h b/libc/src/__support/OSUtil/fcntl.h
new file mode 100644
index 0000000..d934545
--- /dev/null
+++ b/libc/src/__support/OSUtil/fcntl.h
@@ -0,0 +1,17 @@
+//===-- Implementation header of internal fcntl function ------------------===//
+// 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___SUPPORT_OSUTIL_FCNTL_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H
+
+namespace LIBC_NAMESPACE::internal {
+
+int fcntl(int fd, int cmd, void *arg = nullptr);
+
+} // namespace LIBC_NAMESPACE::internal
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_FCNTL_H
diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 9a55232..78b117f 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -8,6 +8,7 @@ add_object_library(
linux_util
SRCS
exit.cpp
+ fcntl.cpp
HDRS
io.h
syscall.h
@@ -15,4 +16,9 @@ add_object_library(
.${LIBC_TARGET_ARCHITECTURE}.linux_${LIBC_TARGET_ARCHITECTURE}_util
libc.src.__support.common
libc.src.__support.CPP.string_view
+ libc.src.errno.errno
+ libc.hdr.fcntl_macros
+ libc.hdr.types.struct_flock
+ libc.hdr.types.struct_flock64
+ libc.hdr.types.struct_f_owner_ex
)
diff --git a/libc/src/__support/OSUtil/linux/fcntl.cpp b/libc/src/__support/OSUtil/linux/fcntl.cpp
new file mode 100644
index 0000000..7dc416a
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/fcntl.cpp
@@ -0,0 +1,94 @@
+//===-- Implementation of internal fcntl ----------------------------------===//
+//
+// 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/__support/OSUtil/fcntl.h"
+
+#include "hdr/fcntl_macros.h"
+#include "hdr/types/struct_f_owner_ex.h"
+#include "hdr/types/struct_flock.h"
+#include "hdr/types/struct_flock64.h"
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/errno/libc_errno.h"
+
+#include <stdarg.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE::internal {
+
+int fcntl(int fd, int cmd, void *arg) {
+ switch (cmd) {
+ case F_OFD_SETLKW: {
+ struct flock *flk = reinterpret_cast<struct flock *>(arg);
+ // convert the struct to a flock64
+ struct flock64 flk64;
+ flk64.l_type = flk->l_type;
+ flk64.l_whence = flk->l_whence;
+ flk64.l_start = flk->l_start;
+ flk64.l_len = flk->l_len;
+ flk64.l_pid = flk->l_pid;
+ // create a syscall
+ return LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
+ }
+ case F_OFD_GETLK:
+ case F_OFD_SETLK: {
+ struct flock *flk = reinterpret_cast<struct flock *>(arg);
+ // convert the struct to a flock64
+ struct flock64 flk64;
+ flk64.l_type = flk->l_type;
+ flk64.l_whence = flk->l_whence;
+ flk64.l_start = flk->l_start;
+ flk64.l_len = flk->l_len;
+ flk64.l_pid = flk->l_pid;
+ // create a syscall
+ int retVal = LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
+ // On failure, return
+ if (retVal == -1)
+ return -1;
+ // Check for overflow, i.e. the offsets are not the same when cast
+ // to off_t from off64_t.
+ if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
+ static_cast<off_t>(flk64.l_start) != flk64.l_start) {
+ libc_errno = EOVERFLOW;
+ return -1;
+ }
+ // Now copy back into flk, in case flk64 got modified
+ flk->l_type = flk64.l_type;
+ flk->l_whence = flk64.l_whence;
+ flk->l_start = flk64.l_start;
+ flk->l_len = flk64.l_len;
+ flk->l_pid = flk64.l_pid;
+ return retVal;
+ }
+ case F_GETOWN: {
+ struct f_owner_ex fex;
+ int retVal =
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, F_GETOWN_EX, &fex);
+ if (retVal == -EINVAL)
+ return LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd,
+ reinterpret_cast<void *>(arg));
+ if (static_cast<unsigned long>(retVal) <= -4096UL)
+ return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid;
+
+ libc_errno = -retVal;
+ return -1;
+ }
+ // The general case
+ default: {
+ int retVal = LIBC_NAMESPACE::syscall_impl<int>(
+ SYS_fcntl, fd, cmd, reinterpret_cast<void *>(arg));
+ if (retVal >= 0) {
+ return retVal;
+ }
+ libc_errno = -retVal;
+ return -1;
+ }
+ }
+}
+
+} // namespace LIBC_NAMESPACE::internal
diff --git a/libc/src/fcntl/linux/CMakeLists.txt b/libc/src/fcntl/linux/CMakeLists.txt
index 732b7be..ee8ae63 100644
--- a/libc/src/fcntl/linux/CMakeLists.txt
+++ b/libc/src/fcntl/linux/CMakeLists.txt
@@ -18,12 +18,7 @@ add_entrypoint_object(
../fcntl.h
DEPENDS
libc.include.fcntl
- libc.hdr.types.struct_flock
- libc.hdr.types.struct_flock64
- libc.hdr.types.struct_f_owner_ex
- libc.hdr.fcntl_macros
libc.src.__support.OSUtil.osutil
- libc.src.errno.errno
)
add_entrypoint_object(
diff --git a/libc/src/fcntl/linux/fcntl.cpp b/libc/src/fcntl/linux/fcntl.cpp
index 24a20fb..3875889 100644
--- a/libc/src/fcntl/linux/fcntl.cpp
+++ b/libc/src/fcntl/linux/fcntl.cpp
@@ -8,86 +8,20 @@
#include "src/fcntl/fcntl.h"
-#include "hdr/fcntl_macros.h"
-#include "hdr/types/struct_f_owner_ex.h"
-#include "hdr/types/struct_flock.h"
-#include "hdr/types/struct_flock64.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/fcntl.h"
#include "src/__support/common.h"
-#include "src/errno/libc_errno.h"
#include <stdarg.h>
-#include <sys/syscall.h> // For syscall numbers.
-// The OFD file locks require special handling for LARGEFILES
namespace LIBC_NAMESPACE {
+
LLVM_LIBC_FUNCTION(int, fcntl, (int fd, int cmd, ...)) {
void *arg;
va_list varargs;
va_start(varargs, cmd);
arg = va_arg(varargs, void *);
va_end(varargs);
-
- switch (cmd) {
- case F_SETLKW:
- return syscall_impl<int>(SYS_fcntl, fd, cmd, arg);
- case F_OFD_SETLKW: {
- struct flock *flk = reinterpret_cast<struct flock *>(arg);
- // convert the struct to a flock64
- struct flock64 flk64;
- flk64.l_type = flk->l_type;
- flk64.l_whence = flk->l_whence;
- flk64.l_start = flk->l_start;
- flk64.l_len = flk->l_len;
- flk64.l_pid = flk->l_pid;
- // create a syscall
- return syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
- }
- case F_OFD_GETLK:
- case F_OFD_SETLK: {
- struct flock *flk = reinterpret_cast<struct flock *>(arg);
- // convert the struct to a flock64
- struct flock64 flk64;
- flk64.l_type = flk->l_type;
- flk64.l_whence = flk->l_whence;
- flk64.l_start = flk->l_start;
- flk64.l_len = flk->l_len;
- flk64.l_pid = flk->l_pid;
- // create a syscall
- int retVal = syscall_impl<int>(SYS_fcntl, fd, cmd, &flk64);
- // On failure, return
- if (retVal == -1)
- return -1;
- // Check for overflow, i.e. the offsets are not the same when cast
- // to off_t from off64_t.
- if (static_cast<off_t>(flk64.l_len) != flk64.l_len ||
- static_cast<off_t>(flk64.l_start) != flk64.l_start) {
- libc_errno = EOVERFLOW;
- return -1;
- }
- // Now copy back into flk, in case flk64 got modified
- flk->l_type = flk64.l_type;
- flk->l_whence = flk64.l_whence;
- flk->l_start = flk64.l_start;
- flk->l_len = flk64.l_len;
- flk->l_pid = flk64.l_pid;
- return retVal;
- }
- case F_GETOWN: {
- struct f_owner_ex fex;
- int retVal = syscall_impl<int>(SYS_fcntl, fd, F_GETOWN_EX, &fex);
- if (retVal == -EINVAL)
- return syscall_impl<int>(SYS_fcntl, fd, cmd,
- reinterpret_cast<void *>(arg));
- if (static_cast<unsigned long>(retVal) <= -4096UL)
- return fex.type == F_OWNER_PGRP ? -fex.pid : fex.pid;
-
- libc_errno = -retVal;
- return -1;
- }
- // The general case
- default:
- return syscall_impl<int>(SYS_fcntl, fd, cmd, reinterpret_cast<void *>(arg));
- }
+ return LIBC_NAMESPACE::internal::fcntl(fd, cmd, arg);
}
+
} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 7cf3278..a659d9e 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -230,6 +230,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.rename
)
+add_entrypoint_object(
+ fdopen
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.fdopen
+)
+
# These entrypoints have multiple potential implementations.
add_stdio_entrypoint_object(feof)
add_stdio_entrypoint_object(feof_unlocked)
diff --git a/libc/src/stdio/fdopen.h b/libc/src/stdio/fdopen.h
new file mode 100644
index 0000000..158a133e
--- /dev/null
+++ b/libc/src/stdio/fdopen.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of open ---------------------------*- 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 <stdio.h>
+
+namespace LIBC_NAMESPACE {
+
+FILE *fdopen(int fd, const char *mode);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDIO_FDOPEN_H
diff --git a/libc/src/stdio/linux/CMakeLists.txt b/libc/src/stdio/linux/CMakeLists.txt
index a08ff0b..fa36732 100644
--- a/libc/src/stdio/linux/CMakeLists.txt
+++ b/libc/src/stdio/linux/CMakeLists.txt
@@ -24,3 +24,15 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
+
+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
+)
diff --git a/libc/src/stdio/linux/fdopen.cpp b/libc/src/stdio/linux/fdopen.cpp
new file mode 100644
index 0000000..a1d08ee
--- /dev/null
+++ b/libc/src/stdio/linux/fdopen.cpp
@@ -0,0 +1,25 @@
+//===-- Implementation 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fdopen.h"
+
+#include "src/__support/File/linux/file.h"
+#include "src/errno/libc_errno.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(::FILE *, fdopen, (int fd, const char *mode)) {
+ auto result = LIBC_NAMESPACE::create_file_from_fd(fd, mode);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return nullptr;
+ }
+ return reinterpret_cast<::FILE *>(result.value());
+}
+
+} // namespace LIBC_NAMESPACE