File indexing completed on 2024-05-05 05:50:39
0001 /* 0002 SPDX-FileCopyrightText: 2007 Henrique Pinto <henrique.pinto@kdemail.net> 0003 SPDX-FileCopyrightText: 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no> 0004 SPDX-FileCopyrightText: 2009-2012 Raphael Kubo da Costa <rakuco@FreeBSD.org> 0005 SPDX-FileCopyrightText: 2016 Vladyslav Batyrenko <mvlabat@gmail.com> 0006 0007 SPDX-License-Identifier: BSD-2-Clause 0008 */ 0009 0010 #include "archiveinterface.h" 0011 #include "ark_debug.h" 0012 #include "jobs.h" 0013 #include "mimetypes.h" 0014 #include "windows_stat.h" 0015 0016 #include <QDir> 0017 #include <QFileInfo> 0018 0019 namespace Kerfuffle 0020 { 0021 ReadOnlyArchiveInterface::ReadOnlyArchiveInterface(QObject *parent, const QVariantList &args) 0022 : QObject(parent) 0023 , m_numberOfVolumes(0) 0024 , m_numberOfEntries(0) 0025 , m_waitForFinishedSignal(false) 0026 , m_isHeaderEncryptionEnabled(false) 0027 , m_isCorrupt(false) 0028 , m_isMultiVolume(false) 0029 , m_unpackedSize(0) 0030 { 0031 Q_ASSERT(args.size() >= 2); 0032 qRegisterMetaType<Kerfuffle::Query *>(); 0033 0034 qCDebug(ARK) << "Created read-only interface for" << args.first().toString(); 0035 m_filename = args.first().toString(); 0036 m_mimetype = determineMimeType(m_filename); 0037 connect(this, &ReadOnlyArchiveInterface::entry, this, &ReadOnlyArchiveInterface::onEntry); 0038 m_metaData = args.at(1).value<KPluginMetaData>(); 0039 } 0040 0041 ReadOnlyArchiveInterface::~ReadOnlyArchiveInterface() 0042 { 0043 } 0044 0045 void ReadOnlyArchiveInterface::onEntry(Archive::Entry *archiveEntry) 0046 { 0047 Q_ASSERT(archiveEntry); 0048 m_numberOfEntries += 1; 0049 m_unpackedSize += archiveEntry->isSparse() ? archiveEntry->sparseSize() : archiveEntry->size(); 0050 } 0051 0052 QString ReadOnlyArchiveInterface::filename() const 0053 { 0054 return m_filename; 0055 } 0056 0057 QString ReadOnlyArchiveInterface::comment() const 0058 { 0059 return m_comment; 0060 } 0061 0062 bool ReadOnlyArchiveInterface::isReadOnly() const 0063 { 0064 return true; 0065 } 0066 0067 bool ReadOnlyArchiveInterface::open() 0068 { 0069 return true; 0070 } 0071 0072 void ReadOnlyArchiveInterface::setPassword(const QString &password) 0073 { 0074 m_password = password; 0075 } 0076 0077 void ReadOnlyArchiveInterface::setHeaderEncryptionEnabled(bool enabled) 0078 { 0079 m_isHeaderEncryptionEnabled = enabled; 0080 } 0081 0082 QString ReadOnlyArchiveInterface::password() const 0083 { 0084 return m_password; 0085 } 0086 0087 bool ReadOnlyArchiveInterface::doKill() 0088 { 0089 // default implementation 0090 return false; 0091 } 0092 0093 void ReadOnlyArchiveInterface::setCorrupt(bool isCorrupt) 0094 { 0095 m_isCorrupt = isCorrupt; 0096 } 0097 0098 bool ReadOnlyArchiveInterface::isCorrupt() const 0099 { 0100 return m_isCorrupt; 0101 } 0102 0103 bool ReadOnlyArchiveInterface::isMultiVolume() const 0104 { 0105 return m_isMultiVolume; 0106 } 0107 0108 void ReadOnlyArchiveInterface::setMultiVolume(bool value) 0109 { 0110 m_isMultiVolume = value; 0111 } 0112 0113 int ReadOnlyArchiveInterface::numberOfVolumes() const 0114 { 0115 return m_numberOfVolumes; 0116 } 0117 0118 QString ReadOnlyArchiveInterface::multiVolumeName() const 0119 { 0120 return filename(); 0121 } 0122 0123 ReadWriteArchiveInterface::ReadWriteArchiveInterface(QObject *parent, const QVariantList &args) 0124 : ReadOnlyArchiveInterface(parent, args) 0125 { 0126 qCDebug(ARK) << "Created read-write interface for" << args.first().toString(); 0127 0128 connect(this, &ReadWriteArchiveInterface::entryRemoved, this, &ReadWriteArchiveInterface::onEntryRemoved); 0129 } 0130 0131 ReadWriteArchiveInterface::~ReadWriteArchiveInterface() 0132 { 0133 } 0134 0135 bool ReadOnlyArchiveInterface::waitForFinishedSignal() 0136 { 0137 return m_waitForFinishedSignal; 0138 } 0139 0140 int ReadOnlyArchiveInterface::moveRequiredSignals() const 0141 { 0142 return 1; 0143 } 0144 0145 int ReadOnlyArchiveInterface::copyRequiredSignals() const 0146 { 0147 return 1; 0148 } 0149 0150 void ReadOnlyArchiveInterface::setWaitForFinishedSignal(bool value) 0151 { 0152 m_waitForFinishedSignal = value; 0153 } 0154 0155 qulonglong ReadOnlyArchiveInterface::unpackedSize() const 0156 { 0157 return m_unpackedSize; 0158 } 0159 0160 QString ReadOnlyArchiveInterface::permissionsToString(mode_t perm) 0161 { 0162 QString modeval; 0163 if ((perm & S_IFMT) == QT_STAT_DIR) { 0164 modeval.append(QLatin1Char('d')); 0165 } else if ((perm & S_IFMT) == QT_STAT_LNK) { 0166 modeval.append(QLatin1Char('l')); 0167 } else { 0168 modeval.append(QLatin1Char('-')); 0169 } 0170 modeval.append((perm & S_IRUSR) ? QLatin1Char('r') : QLatin1Char('-')); 0171 modeval.append((perm & S_IWUSR) ? QLatin1Char('w') : QLatin1Char('-')); 0172 if ((perm & S_ISUID) && (perm & S_IXUSR)) { 0173 modeval.append(QLatin1Char('s')); 0174 } else if ((perm & S_ISUID)) { 0175 modeval.append(QLatin1Char('S')); 0176 } else if ((perm & S_IXUSR)) { 0177 modeval.append(QLatin1Char('x')); 0178 } else { 0179 modeval.append(QLatin1Char('-')); 0180 } 0181 modeval.append((perm & S_IRGRP) ? QLatin1Char('r') : QLatin1Char('-')); 0182 modeval.append((perm & S_IWGRP) ? QLatin1Char('w') : QLatin1Char('-')); 0183 if ((perm & S_ISGID) && (perm & S_IXGRP)) { 0184 modeval.append(QLatin1Char('s')); 0185 } else if ((perm & S_ISGID)) { 0186 modeval.append(QLatin1Char('S')); 0187 } else if ((perm & S_IXGRP)) { 0188 modeval.append(QLatin1Char('x')); 0189 } else { 0190 modeval.append(QLatin1Char('-')); 0191 } 0192 modeval.append((perm & S_IROTH) ? QLatin1Char('r') : QLatin1Char('-')); 0193 modeval.append((perm & S_IWOTH) ? QLatin1Char('w') : QLatin1Char('-')); 0194 if ((perm & S_ISVTX) && (perm & S_IXOTH)) { 0195 modeval.append(QLatin1Char('t')); 0196 } else if ((perm & S_ISVTX)) { 0197 modeval.append(QLatin1Char('T')); 0198 } else if ((perm & S_IXOTH)) { 0199 modeval.append(QLatin1Char('x')); 0200 } else { 0201 modeval.append(QLatin1Char('-')); 0202 } 0203 return modeval; 0204 } 0205 0206 QStringList ReadOnlyArchiveInterface::entryFullPaths(const QVector<Archive::Entry *> &entries, PathFormat format) 0207 { 0208 QStringList filesList; 0209 for (const Archive::Entry *file : entries) { 0210 filesList << file->fullPath(format); 0211 } 0212 return filesList; 0213 } 0214 0215 QVector<Archive::Entry *> ReadOnlyArchiveInterface::entriesWithoutChildren(const QVector<Archive::Entry *> &entries) 0216 { 0217 // QMap is easy way to get entries sorted by their fullPath. 0218 QMap<QString, Archive::Entry *> sortedEntries; 0219 for (Archive::Entry *entry : entries) { 0220 sortedEntries.insert(entry->fullPath(), entry); 0221 } 0222 0223 QVector<Archive::Entry *> filteredEntries; 0224 QString lastFolder; 0225 for (Archive::Entry *entry : std::as_const(sortedEntries)) { 0226 if (!lastFolder.isEmpty() && entry->fullPath().startsWith(lastFolder)) { 0227 continue; 0228 } 0229 0230 lastFolder = (entry->fullPath().right(1) == QLatin1String("/")) ? entry->fullPath() : QString(); 0231 filteredEntries << entry; 0232 } 0233 0234 return filteredEntries; 0235 } 0236 0237 QStringList ReadOnlyArchiveInterface::entryPathsFromDestination(QStringList entries, const Archive::Entry *destination, int entriesWithoutChildren) 0238 { 0239 QStringList paths = QStringList(); 0240 entries.sort(); 0241 QString lastFolder; 0242 const QString destinationPath = (destination == nullptr) ? QString() : destination->fullPath(); 0243 0244 QString newPath; 0245 int nameLength = 0; 0246 for (const QString &entryPath : std::as_const(entries)) { 0247 if (!lastFolder.isEmpty() && entryPath.startsWith(lastFolder)) { 0248 // Replace last moved or copied folder path with destination path. 0249 int charsCount = entryPath.length() - lastFolder.length(); 0250 if (entriesWithoutChildren != 1) { 0251 charsCount += nameLength; 0252 } 0253 newPath = destinationPath + entryPath.right(charsCount); 0254 } else { 0255 const QString name = entryPath.split(QLatin1Char('/'), Qt::SkipEmptyParts).last(); 0256 if (entriesWithoutChildren != 1) { 0257 newPath = destinationPath + name; 0258 if (entryPath.right(1) == QLatin1String("/")) { 0259 newPath += QLatin1Char('/'); 0260 } 0261 } else { 0262 // If the mode is set to Move and there is only one passed file in the list, 0263 // we have to use destination as newPath. 0264 newPath = destinationPath; 0265 } 0266 if (entryPath.right(1) == QLatin1String("/")) { 0267 nameLength = name.length() + 1; // plus slash 0268 lastFolder = entryPath; 0269 } else { 0270 nameLength = 0; 0271 lastFolder = QString(); 0272 } 0273 } 0274 paths << newPath; 0275 } 0276 0277 return paths; 0278 } 0279 0280 bool ReadOnlyArchiveInterface::isHeaderEncryptionEnabled() const 0281 { 0282 return m_isHeaderEncryptionEnabled; 0283 } 0284 0285 QMimeType ReadOnlyArchiveInterface::mimetype() const 0286 { 0287 return m_mimetype; 0288 } 0289 0290 bool ReadOnlyArchiveInterface::hasBatchExtractionProgress() const 0291 { 0292 return false; 0293 } 0294 0295 bool ReadOnlyArchiveInterface::isLocked() const 0296 { 0297 return false; 0298 } 0299 0300 bool ReadWriteArchiveInterface::isReadOnly() const 0301 { 0302 if (isLocked()) { 0303 return true; 0304 } 0305 0306 // We set corrupt archives to read-only to avoid add/delete actions, that 0307 // are likely to fail anyway. 0308 if (isCorrupt()) { 0309 return true; 0310 } 0311 0312 QFileInfo fileInfo(filename()); 0313 if (fileInfo.exists()) { 0314 return !fileInfo.isWritable(); 0315 } else { 0316 return !fileInfo.dir().exists(); // TODO: Should also check if we can create a file in that directory 0317 } 0318 } 0319 0320 uint ReadOnlyArchiveInterface::numberOfEntries() const 0321 { 0322 return m_numberOfEntries; 0323 } 0324 0325 void ReadWriteArchiveInterface::onEntryRemoved(const QString &path) 0326 { 0327 Q_UNUSED(path) 0328 m_numberOfEntries--; 0329 } 0330 0331 } // namespace Kerfuffle 0332 0333 #include "moc_archiveinterface.cpp"