diff options
Diffstat (limited to 'drivers/unix/file_access_unix_pipe.cpp')
-rw-r--r-- | drivers/unix/file_access_unix_pipe.cpp | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp new file mode 100644 index 0000000000..5d9a27ad05 --- /dev/null +++ b/drivers/unix/file_access_unix_pipe.cpp @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* file_access_unix_pipe.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "file_access_unix_pipe.h" + +#if defined(UNIX_ENABLED) + +#include "core/os/os.h" +#include "core/string/print_string.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +Error FileAccessUnixPipe::open_existing(int p_rfd, int p_wfd) { + // Open pipe using handles created by pipe(fd) call in the OS.execute_with_pipe. + _close(); + + path_src = String(); + unlink_on_close = false; + ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); + fd[0] = p_rfd; + fd[1] = p_wfd; + + last_error = OK; + return OK; +} + +Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags) { + _close(); + + path_src = p_path; + ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); + + path = String("/tmp/") + p_path.replace("pipe://", "").replace("/", "_"); + struct stat st = {}; + int err = stat(path.utf8().get_data(), &st); + if (err) { + if (mkfifo(path.utf8().get_data(), 0666) != 0) { + last_error = ERR_FILE_CANT_OPEN; + return last_error; + } + unlink_on_close = true; + } else { + ERR_FAIL_COND_V_MSG(!S_ISFIFO(st.st_mode), ERR_ALREADY_IN_USE, "Pipe name is already used by file."); + } + + int f = ::open(path.utf8().get_data(), O_RDWR | O_CLOEXEC); + if (f < 0) { + switch (errno) { + case ENOENT: { + last_error = ERR_FILE_NOT_FOUND; + } break; + default: { + last_error = ERR_FILE_CANT_OPEN; + } break; + } + return last_error; + } + + // Set close on exec to avoid leaking it to subprocesses. + fd[0] = f; + fd[1] = f; + + last_error = OK; + return OK; +} + +void FileAccessUnixPipe::_close() { + if (fd[0] < 0) { + return; + } + + if (fd[1] != fd[0]) { + ::close(fd[1]); + } + ::close(fd[0]); + fd[0] = -1; + fd[1] = -1; + + if (unlink_on_close) { + ::unlink(path.utf8().ptr()); + } + unlink_on_close = false; +} + +bool FileAccessUnixPipe::is_open() const { + return (fd[0] >= 0 || fd[1] >= 0); +} + +String FileAccessUnixPipe::get_path() const { + return path_src; +} + +String FileAccessUnixPipe::get_path_absolute() const { + return path_src; +} + +uint8_t FileAccessUnixPipe::get_8() const { + ERR_FAIL_COND_V_MSG(fd[0] < 0, 0, "Pipe must be opened before use."); + + uint8_t b; + if (::read(fd[0], &b, 1) == 0) { + last_error = ERR_FILE_CANT_READ; + b = '\0'; + } else { + last_error = OK; + } + return b; +} + +uint64_t FileAccessUnixPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + ERR_FAIL_COND_V_MSG(fd[0] < 0, -1, "Pipe must be opened before use."); + + uint64_t read = ::read(fd[0], p_dst, p_length); + if (read == p_length) { + last_error = ERR_FILE_CANT_READ; + } else { + last_error = OK; + } + return read; +} + +Error FileAccessUnixPipe::get_error() const { + return last_error; +} + +void FileAccessUnixPipe::store_8(uint8_t p_src) { + ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use."); + if (::write(fd[1], &p_src, 1) != 1) { + last_error = ERR_FILE_CANT_WRITE; + } else { + last_error = OK; + } +} + +void FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use."); + ERR_FAIL_COND(!p_src && p_length > 0); + if (::write(fd[1], p_src, p_length) != (ssize_t)p_length) { + last_error = ERR_FILE_CANT_WRITE; + } else { + last_error = OK; + } +} + +void FileAccessUnixPipe::close() { + _close(); +} + +FileAccessUnixPipe::~FileAccessUnixPipe() { + _close(); +} + +#endif // UNIX_ENABLED |