File indexing completed on 2024-11-10 04:57:22
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2022 MBition GmbH 0006 SPDX-FileContributor: Kai Uwe Broulik <kai_uwe.broulik@mbition.io> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "ramfile.h" 0012 #include "common.h" // for logging 0013 0014 #include <QScopeGuard> 0015 0016 #include <cerrno> 0017 #include <fcntl.h> 0018 #include <sys/mman.h> 0019 #include <unistd.h> 0020 #include <utility> 0021 0022 namespace KWin 0023 { 0024 0025 RamFile::RamFile(const char *name, const void *inData, int size, RamFile::Flags flags) 0026 : m_size(size) 0027 , m_flags(flags) 0028 { 0029 auto guard = qScopeGuard([this] { 0030 cleanup(); 0031 }); 0032 0033 #if HAVE_MEMFD 0034 m_fd = FileDescriptor(memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING)); 0035 if (!m_fd.isValid()) { 0036 qCWarning(KWIN_CORE).nospace() << name << ": Can't create memfd: " << strerror(errno); 0037 return; 0038 } 0039 0040 if (ftruncate(m_fd.get(), size) < 0) { 0041 qCWarning(KWIN_CORE).nospace() << name << ": Failed to ftruncate memfd: " << strerror(errno); 0042 return; 0043 } 0044 0045 void *data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd.get(), 0); 0046 if (data == MAP_FAILED) { 0047 qCWarning(KWIN_CORE).nospace() << name << ": mmap failed: " << strerror(errno); 0048 return; 0049 } 0050 #else 0051 m_tmp = std::make_unique<QTemporaryFile>(); 0052 if (!m_tmp->open()) { 0053 qCWarning(KWIN_CORE).nospace() << name << ": Can't open temporary file"; 0054 return; 0055 } 0056 0057 if (unlink(m_tmp->fileName().toUtf8().constData()) != 0) { 0058 qCWarning(KWIN_CORE).nospace() << name << ": Failed to remove temporary file from filesystem: " << strerror(errno); 0059 } 0060 0061 if (!m_tmp->resize(size)) { 0062 qCWarning(KWIN_CORE).nospace() << name << ": Failed to resize temporary file"; 0063 return; 0064 } 0065 0066 uchar *data = m_tmp->map(0, size); 0067 if (!data) { 0068 qCWarning(KWIN_CORE).nospace() << name << ": map failed"; 0069 return; 0070 } 0071 #endif 0072 0073 memcpy(data, inData, size); 0074 0075 #if HAVE_MEMFD 0076 munmap(data, size); 0077 #else 0078 m_tmp->unmap(data); 0079 #endif 0080 0081 int seals = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL; 0082 if (flags.testFlag(RamFile::Flag::SealWrite)) { 0083 seals |= F_SEAL_WRITE; 0084 } 0085 // This can fail for QTemporaryFile based on the underlying file system. 0086 if (fcntl(fd(), F_ADD_SEALS, seals) != 0) { 0087 qCDebug(KWIN_CORE).nospace() << name << ": Failed to seal RamFile: " << strerror(errno); 0088 } 0089 0090 guard.dismiss(); 0091 } 0092 0093 RamFile::RamFile(RamFile &&other) Q_DECL_NOEXCEPT 0094 : m_size(std::exchange(other.m_size, 0)) 0095 , m_flags(std::exchange(other.m_flags, RamFile::Flags{})) 0096 #if HAVE_MEMFD 0097 , m_fd(std::exchange(other.m_fd, KWin::FileDescriptor{})) 0098 #else 0099 , m_tmp(std::exchange(other.m_tmp, {})) 0100 #endif 0101 { 0102 } 0103 0104 RamFile &RamFile::operator=(RamFile &&other) Q_DECL_NOEXCEPT 0105 { 0106 cleanup(); 0107 m_size = std::exchange(other.m_size, 0); 0108 m_flags = std::exchange(other.m_flags, RamFile::Flags{}); 0109 #if HAVE_MEMFD 0110 m_fd = std::exchange(other.m_fd, KWin::FileDescriptor{}); 0111 #else 0112 m_tmp = std::exchange(other.m_tmp, {}); 0113 #endif 0114 return *this; 0115 } 0116 0117 RamFile::~RamFile() 0118 { 0119 cleanup(); 0120 } 0121 0122 void RamFile::cleanup() 0123 { 0124 #if HAVE_MEMFD 0125 m_fd = KWin::FileDescriptor(); 0126 #else 0127 m_tmp.reset(); 0128 #endif 0129 } 0130 0131 bool RamFile::isValid() const 0132 { 0133 return fd() != -1; 0134 } 0135 0136 RamFile::Flags RamFile::effectiveFlags() const 0137 { 0138 Flags flags = {}; 0139 0140 const int seals = fcntl(fd(), F_GET_SEALS); 0141 if (seals > 0) { 0142 if (seals & F_SEAL_WRITE) { 0143 flags.setFlag(Flag::SealWrite); 0144 } 0145 } 0146 0147 return flags; 0148 } 0149 0150 int RamFile::fd() const 0151 { 0152 #if HAVE_MEMFD 0153 return m_fd.get(); 0154 #else 0155 return m_tmp->handle(); 0156 #endif 0157 } 0158 0159 int RamFile::size() const 0160 { 0161 return m_size; 0162 } 0163 0164 } // namespace KWin