diff options
Diffstat (limited to 'libc/src/__support/File/linux/file.cpp')
| -rw-r--r-- | libc/src/__support/File/linux/file.cpp | 58 |
1 files changed, 56 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(); |
