From 218bae491f73215893f69be8dae6bf7478bf09e8 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 20 Nov 2024 13:50:10 +0100 Subject: [PATCH] filedescriptor: implent a new FileDescriptor class makes you able to RAII the filedescriptor making it somewhat easier to not leak. --- include/hyprutils/utils/FileDescriptor.hpp | 39 ++++++++++ src/utils/FileDescriptor.cpp | 89 ++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 include/hyprutils/utils/FileDescriptor.hpp create mode 100644 src/utils/FileDescriptor.cpp diff --git a/include/hyprutils/utils/FileDescriptor.hpp b/include/hyprutils/utils/FileDescriptor.hpp new file mode 100644 index 0000000..029e9b9 --- /dev/null +++ b/include/hyprutils/utils/FileDescriptor.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +namespace Hyprutils { + namespace Utils { + class CFileDescriptor { + public: + CFileDescriptor() = default; + explicit CFileDescriptor(int const fd); + CFileDescriptor(CFileDescriptor&&); + CFileDescriptor& operator=(CFileDescriptor&&); + ~CFileDescriptor(); + + CFileDescriptor(const CFileDescriptor&) = delete; + CFileDescriptor& operator=(const CFileDescriptor&) = delete; + + bool operator==(const CFileDescriptor& rhs) const { + return m_fd == rhs.m_fd; + } + + bool isValid() const; + int get() const; + int getFlags() const; + bool setFlags(int flags); + int take(); + void reset(); + CFileDescriptor duplicate(int flags = F_DUPFD_CLOEXEC) const; + + bool isReadable() const; + bool isClosed() const; + + static bool isReadable(int fd); + static bool isClosed(int fd); + + private: + int m_fd = -1; + }; + }; +}; diff --git a/src/utils/FileDescriptor.cpp b/src/utils/FileDescriptor.cpp new file mode 100644 index 0000000..dcae69d --- /dev/null +++ b/src/utils/FileDescriptor.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + +using namespace Hyprutils::Utils; + +CFileDescriptor::CFileDescriptor(int const fd) : m_fd(fd) {} + +CFileDescriptor::CFileDescriptor(CFileDescriptor&& other) : m_fd(std::exchange(other.m_fd, -1)) {} + +CFileDescriptor& CFileDescriptor::operator=(CFileDescriptor&& other) { + if (this == &other) // Shit will go haywire if there is duplicate ownership + abort(); + + reset(); + m_fd = std::exchange(other.m_fd, -1); + return *this; +} + +CFileDescriptor::~CFileDescriptor() { + reset(); +} + +bool CFileDescriptor::isValid() const { + return m_fd != -1; +} + +int CFileDescriptor::get() const { + return m_fd; +} + +int CFileDescriptor::getFlags() const { + return fcntl(m_fd, F_GETFD); +} + +bool CFileDescriptor::setFlags(int flags) { + if (fcntl(m_fd, F_SETFD, flags) == -1) + return false; + + return true; +} + +int CFileDescriptor::take() { + return std::exchange(m_fd, -1); +} + +void CFileDescriptor::reset() { + if (m_fd != -1) { + close(m_fd); + m_fd = -1; + } +} + +CFileDescriptor CFileDescriptor::duplicate(int flags) const { + if (m_fd == -1) + return {}; + + return CFileDescriptor{fcntl(m_fd, flags, 0)}; +} + +bool CFileDescriptor::isClosed() const { + return isClosed(m_fd); +} + +bool CFileDescriptor::isReadable() const { + return isReadable(m_fd); +} + +bool CFileDescriptor::isClosed(int fd) { + pollfd pfd = { + .fd = fd, + .events = POLLIN, + .revents = 0, + }; + + if (poll(&pfd, 1, 0) < 0) + return true; + + return pfd.revents & (POLLHUP | POLLERR); +} + +bool CFileDescriptor::isReadable(int fd) { + pollfd pfd = {.fd = fd, .events = POLLIN, .revents = 0}; + + return poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN); +}