diff options
| author | Xu Zhang <simonzgx@gmail.com> | 2024-06-15 07:17:44 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-14 16:17:44 -0700 |
| commit | 0b24b4706982907799c838d80e06b3aa08420549 (patch) | |
| tree | 7943efb95051d5f516004ad1687883e4ab737909 /libc/src/__support/File | |
| parent | 98b117e4355d2ba7b672014aafc41b3f646fc72c (diff) | |
[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/__support/File')
| -rw-r--r-- | libc/src/__support/File/linux/file.cpp | 58 | ||||
| -rw-r--r-- | libc/src/__support/File/linux/file.h | 3 |
2 files changed, 59 insertions, 2 deletions
diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp index b84da64cbe63..00ff93846c6b 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 24e71b133c48..7d3770e1cdd7 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 |
