File indexing completed on 2024-05-12 17:22:24
0001 /* 0002 SPDX-FileCopyrightText: 2003 Rafi Yanai <krusader@users.sf.net> 0003 SPDX-FileCopyrightText: 2003 Shie Erlich <krusader@users.sf.net> 0004 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "krarc.h" 0010 #include "../../app/defaults.h" 0011 0012 // QtCore 0013 #include <QByteArray> 0014 #include <QCoreApplication> 0015 #include <QDebug> 0016 #include <QDir> 0017 #include <QFile> 0018 #include <QFileInfo> 0019 #include <QMimeDatabase> 0020 #include <QMimeType> 0021 #include <QRegExp> 0022 #include <QTemporaryFile> 0023 #include <QTextCodec> 0024 #include <qplatformdefs.h> 0025 0026 #include <KArchive/KTar> 0027 #include <KCoreAddons/KProcess> 0028 #include <KI18n/KLocalizedString> 0029 #include <KIO/Job> 0030 #include <KIOCore/KFileItem> 0031 0032 #include <kio_version.h> 0033 0034 #include "../../app/compat.h" 0035 #include <errno.h> 0036 0037 #define MAX_IPC_SIZE (1024 * 32) 0038 #define TRIES_WITH_PASSWORDS 3 0039 0040 // Pseudo plugin class to embed meta data 0041 class KIOPluginForMetaData : public QObject 0042 { 0043 Q_OBJECT 0044 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0045 Q_PLUGIN_METADATA(IID "org.kde.kio.worker.krarc" FILE "krarc.json") 0046 #else 0047 Q_PLUGIN_METADATA(IID "org.kde.kio.slave.krarc" FILE "krarc.json") 0048 #endif 0049 }; 0050 0051 using namespace KIO; 0052 extern "C" { 0053 0054 #ifdef KRARC_ENABLED 0055 /* This codec is for being able to handle files which encoding differs from the current locale. 0056 * 0057 * Unfortunately QProcess requires QString parameters for arguments which are encoded to Local8Bit 0058 * If we want to use unzip with ISO-8852-2 when the current locale is UTF-8, it will cause problems. 0059 * 0060 * Workaround: 0061 * 1. encode the QString to QByteArray ( according to the selected remote encoding, ISO-8852-2 ) 0062 * 2. encode QByteArray to QString again 0063 * unicode 0xE000-0xF7FF is for private use 0064 * the byte array is mapped to 0xE000-0xE0FF unicodes 0065 * 3. KrArcCodec maps 0xE000-0xE0FF to 0x0000-0x00FF, while calls the default encoding routine 0066 * for other unicodes. 0067 */ 0068 0069 class KrArcCodec : public QTextCodec 0070 { 0071 public: 0072 KrArcCodec(QTextCodec *codec) 0073 : originalCodec(codec) 0074 { 0075 } 0076 ~KrArcCodec() override = default; 0077 0078 QByteArray name() const override 0079 { 0080 return originalCodec->name(); 0081 } 0082 QList<QByteArray> aliases() const override 0083 { 0084 return originalCodec->aliases(); 0085 } 0086 int mibEnum() const override 0087 { 0088 return originalCodec->mibEnum(); 0089 } 0090 0091 protected: 0092 QString convertToUnicode(const char *in, int length, ConverterState *state) const override 0093 { 0094 return originalCodec->toUnicode(in, length, state); 0095 } 0096 QByteArray convertFromUnicode(const QChar *in, int length, ConverterState *state) const override 0097 { 0098 // the QByteArray is embedded into the unicode charset (QProcess hell) 0099 QByteArray result; 0100 for (int i = 0; i != length; i++) { 0101 if (((in[i].unicode()) & 0xFF00) == 0xE000) // map 0xE000-0xE0FF to 0x0000-0x00FF 0102 result.append((char)(in[i].unicode() & 0xFF)); 0103 else 0104 result.append(originalCodec->fromUnicode(in + i, 1, state)); 0105 } 0106 return result; 0107 } 0108 0109 private: 0110 QTextCodec *originalCodec; 0111 } *krArcCodec; 0112 0113 #define SET_KRCODEC \ 0114 QTextCodec *origCodec = QTextCodec::codecForLocale(); \ 0115 QTextCodec::setCodecForLocale(krArcCodec); 0116 #define RESET_KRCODEC QTextCodec::setCodecForLocale(origCodec); 0117 0118 #endif // KRARC_ENABLED 0119 0120 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0121 class DummyWorker : public KIO::WorkerBase 0122 #else 0123 class DummySlave : public KIO::SlaveBase 0124 #endif 0125 { 0126 public: 0127 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0128 DummyWorker(const QByteArray &pool_socket, const QByteArray &app_socket) 0129 : WorkerBase("kio_krarc", pool_socket, app_socket){ 0130 #else 0131 DummySlave(const QByteArray &pool_socket, const QByteArray &app_socket) 0132 : SlaveBase("kio_krarc", pool_socket, app_socket) 0133 { 0134 error((int)ERR_SLAVE_DEFINED, QString("krarc is disabled.")); 0135 #endif 0136 0137 } 0138 }; 0139 0140 int Q_DECL_EXPORT kdemain(int argc, char **argv) 0141 { 0142 if (argc != 4) { 0143 qWarning() << "Usage: kio_krarc protocol domain-socket1 domain-socket2" << QT_ENDL; 0144 exit(-1); 0145 } 0146 0147 // At least, that fixes the empty name in the warning that says: Please fix the "" KIO slave 0148 // There is more information in https://bugs.kde.org/show_bug.cgi?id=384653 0149 QCoreApplication app(argc, argv); 0150 app.setApplicationName(QStringLiteral("kio_krarc")); 0151 0152 #ifdef KRARC_ENABLED 0153 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0154 kio_krarcProtocol worker(argv[2], argv[3]); 0155 #else 0156 kio_krarcProtocol slave(argv[2], argv[3]); 0157 #endif 0158 0159 #else 0160 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0161 DummyWorker worker(argv[2], argv[3]); 0162 #else 0163 DummySlave slave(argv[2], argv[3]); 0164 #endif 0165 0166 #endif 0167 0168 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0169 worker.dispatchLoop(); 0170 #else 0171 slave.dispatchLoop(); 0172 #endif 0173 0174 return 0; 0175 } 0176 0177 } // extern "C" 0178 0179 #ifdef KRARC_ENABLED 0180 kio_krarcProtocol::kio_krarcProtocol(const QByteArray &pool_socket, const QByteArray &app_socket) 0181 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0182 : WorkerBase("kio_krarc", pool_socket, app_socket) 0183 , archiveChanged(true) 0184 , arcFile(nullptr) 0185 , extArcReady(false) 0186 , 0187 #else 0188 : SlaveBase("kio_krarc", pool_socket, app_socket) 0189 , archiveChanged(true) 0190 , arcFile(nullptr) 0191 , extArcReady(false) 0192 , 0193 #endif 0194 password(QString()) 0195 , codec(nullptr) 0196 { 0197 KRFUNC; 0198 KConfigGroup group(&krConf, "General"); 0199 QString tmpDirPath = group.readEntry("Temp Directory", _TempDirectory); 0200 QDir tmpDir(tmpDirPath); 0201 if (!tmpDir.exists()) { 0202 for (int i = 1; i != -1; i = tmpDirPath.indexOf('/', i + 1)) 0203 QDir().mkdir(tmpDirPath.left(i)); 0204 QDir().mkdir(tmpDirPath); 0205 } 0206 0207 arcTempDir = tmpDirPath + DIR_SEPARATOR; 0208 QString dirName = "krArc" + QDateTime::currentDateTime().toString(Qt::ISODate); 0209 dirName.replace(QRegExp(":"), "_"); 0210 tmpDir.mkdir(dirName); 0211 arcTempDir = arcTempDir + dirName + DIR_SEPARATOR; 0212 0213 krArcCodec = new KrArcCodec(QTextCodec::codecForLocale()); 0214 } 0215 0216 /* ---------------------------------------------------------------------------------- */ 0217 kio_krarcProtocol::~kio_krarcProtocol() 0218 { 0219 KRFUNC; 0220 // delete the temp directory 0221 KProcess proc; 0222 proc << fullPathName("rm") << "-rf" << arcTempDir; 0223 proc.start(); 0224 proc.waitForFinished(); 0225 } 0226 0227 /* ---------------------------------------------------------------------------------- */ 0228 0229 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0230 KIO::WorkerResult kio_krarcProtocol::checkWriteSupport() 0231 #else 0232 bool kio_krarcProtocol::checkWriteSupport() 0233 #endif 0234 { 0235 KRFUNC; 0236 krConf.reparseConfiguration(); 0237 if (KConfigGroup(&krConf, "kio_krarc").readEntry("EnableWrite", false)) 0238 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0239 return WorkerResult::pass(); 0240 0241 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, 0242 i18n("krarc: write support is disabled.\n" 0243 "You can enable it on the 'Archives' page in Konfigurator.")); 0244 } 0245 #else 0246 return true; 0247 else { 0248 error(ERR_UNSUPPORTED_ACTION, 0249 i18n("krarc: write support is disabled.\n" 0250 "You can enable it on the 'Archives' page in Konfigurator.")); 0251 return false; 0252 } 0253 } 0254 #endif 0255 0256 void kio_krarcProtocol::receivedData(KProcess *, QByteArray &d) 0257 { 0258 KRFUNC; 0259 const QByteArray &buf(d); 0260 data(buf); 0261 processedSize(d.length()); 0262 decompressedLen += d.length(); 0263 } 0264 0265 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0266 KIO::WorkerResult kio_krarcProtocol::mkdir(const QUrl &url, int permissions) 0267 #else 0268 void kio_krarcProtocol::mkdir(const QUrl &url, int permissions) 0269 #endif 0270 { 0271 KRFUNC; 0272 const QString path = getPath(url); 0273 KRDEBUG(path); 0274 0275 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0276 const auto writeSupportResult = checkWriteSupport(); 0277 if (!writeSupportResult.success()) 0278 return writeSupportResult; 0279 #else 0280 if (!checkWriteSupport()) 0281 return; 0282 #endif 0283 0284 // In case of KIO::mkpath call there is a mkdir call for every path element. 0285 // Therefore the path all the way up to our archive needs to be checked for existence 0286 // and reported as success. 0287 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0288 if (QDir().exists(path)) { 0289 return WorkerResult::pass(); 0290 } 0291 0292 const auto setArcFileResult = setArcFile(url); 0293 if (!setArcFileResult.success()) { 0294 return setArcFileResult; 0295 } 0296 0297 if (newArchiveURL && !initDirDict(url)) { 0298 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, path); 0299 } 0300 0301 if (putCmd.isEmpty()) { 0302 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, i18n("Creating folders is not supported with %1 archives", arcType)); 0303 } 0304 #else 0305 if (QDir().exists(path)) { 0306 finished(); 0307 return; 0308 } 0309 0310 if (!setArcFile(url)) { 0311 error(ERR_CANNOT_ENTER_DIRECTORY, path); 0312 return; 0313 } 0314 0315 if (newArchiveURL && !initDirDict(url)) { 0316 error(ERR_CANNOT_ENTER_DIRECTORY, path); 0317 return; 0318 } 0319 0320 if (putCmd.isEmpty()) { 0321 error(ERR_UNSUPPORTED_ACTION, i18n("Creating folders is not supported with %1 archives", arcType)); 0322 return; 0323 } 0324 #endif 0325 0326 const QString arcFilePath = getPath(arcFile->url()); 0327 0328 if (arcType == "arj" || arcType == "lha") { 0329 QString arcDir = path.mid(arcFilePath.length()); 0330 if (arcDir.right(1) != DIR_SEPARATOR) 0331 arcDir = arcDir + DIR_SEPARATOR; 0332 0333 if (dirDict.find(arcDir) == dirDict.end()) 0334 addNewDir(arcDir); 0335 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0336 return WorkerResult::pass(); 0337 #else 0338 finished(); 0339 return; 0340 #endif 0341 } 0342 0343 QString arcDir = findArcDirectory(url); 0344 QString tempDir = arcDir.mid(1) + path.mid(path.lastIndexOf(DIR_SEPARATOR) + 1); 0345 if (tempDir.right(1) != DIR_SEPARATOR) 0346 tempDir = tempDir + DIR_SEPARATOR; 0347 0348 if (permissions == -1) 0349 permissions = 0777; // set default permissions 0350 0351 QByteArray arcTempDirEnc = arcTempDir.toLocal8Bit(); 0352 for (int i = 0; i < tempDir.length() && i >= 0; i = tempDir.indexOf(DIR_SEPARATOR, i + 1)) { 0353 QByteArray newDirs = encodeString(tempDir.left(i)); 0354 newDirs.prepend(arcTempDirEnc); 0355 QT_MKDIR(newDirs, permissions); 0356 } 0357 0358 if (tempDir.endsWith(DIR_SEPARATOR)) 0359 tempDir.truncate(tempDir.length() - 1); 0360 0361 // pack the directory 0362 KrLinecountingProcess proc; 0363 proc << putCmd << arcFilePath << localeEncodedString(tempDir); 0364 infoMessage(i18n("Creating %1...", url.fileName())); 0365 QDir::setCurrent(arcTempDir); 0366 0367 SET_KRCODEC 0368 proc.start(); 0369 RESET_KRCODEC 0370 0371 proc.waitForFinished(); 0372 0373 // delete the temp directory 0374 QDir().rmdir(arcTempDir); 0375 0376 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { 0377 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0378 return WorkerResult::fail(ERR_CANNOT_WRITE, path + "\n\n" + proc.getErrorMsg()); 0379 #else 0380 error(ERR_CANNOT_WRITE, path + "\n\n" + proc.getErrorMsg()); 0381 return; 0382 #endif 0383 } 0384 0385 // force a refresh of archive information 0386 initDirDict(url, true); 0387 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0388 return WorkerResult::pass(); 0389 #else 0390 finished(); 0391 #endif 0392 } 0393 0394 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0395 KIO::WorkerResult kio_krarcProtocol::put(const QUrl &url, int permissions, KIO::JobFlags flags) 0396 #else 0397 void kio_krarcProtocol::put(const QUrl &url, int permissions, KIO::JobFlags flags) 0398 #endif 0399 { 0400 KRFUNC; 0401 KRDEBUG(getPath(url)); 0402 0403 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0404 const auto writeSupportResult = checkWriteSupport(); 0405 if (!writeSupportResult.success()) 0406 return writeSupportResult; 0407 #else 0408 if (!checkWriteSupport()) 0409 return; 0410 #endif 0411 0412 bool overwrite = !!(flags & KIO::Overwrite); 0413 bool resume = !!(flags & KIO::Resume); 0414 0415 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0416 const auto setArcFileResult = setArcFile(url); 0417 if (!setArcFileResult.success()) { 0418 return setArcFileResult; 0419 } 0420 if (newArchiveURL && !initDirDict(url)) { 0421 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0422 } 0423 0424 if (putCmd.isEmpty()) { 0425 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, i18n("Writing to %1 archives is not supported", arcType)); 0426 } 0427 if (!overwrite && findFileEntry(url)) { 0428 return WorkerResult::fail(ERR_FILE_ALREADY_EXIST, getPath(url)); 0429 } 0430 #else 0431 if (!setArcFile(url)) { 0432 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0433 return; 0434 } 0435 if (newArchiveURL && !initDirDict(url)) { 0436 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0437 return; 0438 } 0439 0440 if (putCmd.isEmpty()) { 0441 error(ERR_UNSUPPORTED_ACTION, i18n("Writing to %1 archives is not supported", arcType)); 0442 return; 0443 } 0444 if (!overwrite && findFileEntry(url)) { 0445 error(ERR_FILE_ALREADY_EXIST, getPath(url)); 0446 return; 0447 } 0448 #endif 0449 0450 QString arcDir = findArcDirectory(url); 0451 if (arcDir.isEmpty()) 0452 KRDEBUG("arcDir is empty."); 0453 0454 QString tempFile = arcDir.mid(1) + getPath(url).mid(getPath(url).lastIndexOf(DIR_SEPARATOR) + 1); 0455 QString tempDir = arcDir.mid(1); 0456 if (tempDir.right(1) != DIR_SEPARATOR) 0457 tempDir = tempDir + DIR_SEPARATOR; 0458 0459 if (permissions == -1) 0460 permissions = 0777; // set default permissions 0461 0462 QByteArray arcTempDirEnc = arcTempDir.toLocal8Bit(); 0463 for (int i = 0; i < tempDir.length() && i >= 0; i = tempDir.indexOf(DIR_SEPARATOR, i + 1)) { 0464 QByteArray newDirs = encodeString(tempDir.left(i)); 0465 newDirs.prepend(arcTempDirEnc); 0466 QT_MKDIR(newDirs, 0755); 0467 } 0468 0469 int fd; 0470 if (resume) { 0471 QByteArray ba = encodeString(tempFile); 0472 ba.prepend(arcTempDirEnc); 0473 fd = QT_OPEN(ba, O_RDWR); // append if resuming 0474 QT_LSEEK(fd, 0, SEEK_END); // Seek to end 0475 } else { 0476 // WABA: Make sure that we keep writing permissions ourselves, 0477 // otherwise we can be in for a surprise on NFS. 0478 mode_t initialMode; 0479 if (permissions != -1) 0480 initialMode = permissions | S_IWUSR | S_IRUSR; 0481 else 0482 initialMode = 0666; 0483 0484 QByteArray ba = encodeString(tempFile); 0485 ba.prepend(arcTempDirEnc); 0486 fd = QT_OPEN(ba, O_CREAT | O_TRUNC | O_WRONLY, initialMode); 0487 } 0488 0489 QByteArray buffer; 0490 int readResult; 0491 bool isIncomplete = false; 0492 do { 0493 dataReq(); 0494 readResult = readData(buffer); 0495 auto bytesWritten = ::write(fd, buffer.data(), buffer.size()); 0496 if (bytesWritten < buffer.size()) { 0497 isIncomplete = true; 0498 break; 0499 } 0500 } while (readResult > 0); 0501 ::close(fd); 0502 0503 if (isIncomplete) { 0504 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0505 return WorkerResult::fail(ERR_CANNOT_WRITE, getPath(url)); 0506 #else 0507 error(ERR_CANNOT_WRITE, getPath(url)); 0508 return; 0509 #endif 0510 } 0511 0512 // pack the file 0513 KrLinecountingProcess proc; 0514 proc << putCmd << getPath(arcFile->url()) << localeEncodedString(tempFile); 0515 infoMessage(i18n("Packing %1...", url.fileName())); 0516 QDir::setCurrent(arcTempDir); 0517 0518 SET_KRCODEC 0519 proc.start(); 0520 RESET_KRCODEC 0521 0522 proc.waitForFinished(); 0523 0524 // remove the files 0525 QDir().rmdir(arcTempDir); 0526 0527 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { 0528 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0529 return WorkerResult::fail(ERR_CANNOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); 0530 #else 0531 error(ERR_CANNOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); 0532 return; 0533 #endif 0534 } 0535 // force a refresh of archive information 0536 initDirDict(url, true); 0537 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0538 return WorkerResult::pass(); 0539 #else 0540 finished(); 0541 #endif 0542 } 0543 0544 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0545 KIO::WorkerResult kio_krarcProtocol::get(const QUrl &url) 0546 #else 0547 void kio_krarcProtocol::get(const QUrl &url) 0548 #endif 0549 { 0550 KRFUNC; 0551 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0552 return get(url, TRIES_WITH_PASSWORDS); 0553 #else 0554 get(url, TRIES_WITH_PASSWORDS); 0555 #endif 0556 } 0557 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0558 KIO::WorkerResult kio_krarcProtocol::get(const QUrl &url, int tries) 0559 #else 0560 void kio_krarcProtocol::get(const QUrl &url, int tries) 0561 #endif 0562 { 0563 KRFUNC; 0564 KRDEBUG(getPath(url)); 0565 bool decompressToFile = false; 0566 0567 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0568 const auto setArcFileResult = setArcFile(url); 0569 if (!setArcFileResult.success()) { 0570 return setArcFileResult; 0571 } 0572 if (newArchiveURL && !initDirDict(url)) { 0573 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0574 } 0575 0576 if (getCmd.isEmpty()) { 0577 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, i18n("Retrieving data from %1 archives is not supported", arcType)); 0578 } 0579 UDSEntry *entry = findFileEntry(url); 0580 if (!entry) { 0581 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, getPath(url)); 0582 } 0583 if (KFileItem(*entry, url).isDir()) { 0584 return WorkerResult::fail(KIO::ERR_IS_DIRECTORY, getPath(url)); 0585 } 0586 #else 0587 if (!setArcFile(url)) { 0588 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0589 return; 0590 } 0591 if (newArchiveURL && !initDirDict(url)) { 0592 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0593 return; 0594 } 0595 0596 if (getCmd.isEmpty()) { 0597 error(ERR_UNSUPPORTED_ACTION, i18n("Retrieving data from %1 archives is not supported", arcType)); 0598 return; 0599 } 0600 UDSEntry *entry = findFileEntry(url); 0601 if (!entry) { 0602 error(KIO::ERR_DOES_NOT_EXIST, getPath(url)); 0603 return; 0604 } 0605 if (KFileItem(*entry, url).isDir()) { 0606 error(KIO::ERR_IS_DIRECTORY, getPath(url)); 0607 return; 0608 } 0609 #endif 0610 0611 KIO::filesize_t expectedSize = KFileItem(*entry, url).size(); 0612 // for RPM files extract the cpio file first 0613 if (!extArcReady && arcType == "rpm") { 0614 KrLinecountingProcess cpio; 0615 cpio << "rpm2cpio" << getPath(arcFile->url(), QUrl::StripTrailingSlash); 0616 cpio.setStandardOutputFile(arcTempDir + "contents.cpio"); 0617 0618 cpio.start(); 0619 cpio.waitForFinished(); 0620 0621 if (cpio.exitStatus() != QProcess::NormalExit || !checkStatus(cpio.exitCode())) { 0622 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0623 return WorkerResult::fail(ERR_CANNOT_READ, getPath(url) + "\n\n" + cpio.getErrorMsg()); 0624 #else 0625 error(ERR_CANNOT_READ, getPath(url) + "\n\n" + cpio.getErrorMsg()); 0626 return; 0627 #endif 0628 } 0629 extArcReady = true; 0630 } 0631 // for DEB files extract the tar file first 0632 if (!extArcReady && arcType == "deb") { 0633 KrLinecountingProcess dpkg; 0634 dpkg << cmd << "--fsys-tarfile" << getPath(arcFile->url(), QUrl::StripTrailingSlash); 0635 dpkg.setStandardOutputFile(arcTempDir + "contents.cpio"); 0636 0637 dpkg.start(); 0638 dpkg.waitForFinished(); 0639 0640 if (dpkg.exitStatus() != QProcess::NormalExit || !checkStatus(dpkg.exitCode())) { 0641 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0642 return WorkerResult::fail(ERR_CANNOT_READ, getPath(url) + "\n\n" + dpkg.getErrorMsg()); 0643 #else 0644 error(ERR_CANNOT_READ, getPath(url) + "\n\n" + dpkg.getErrorMsg()); 0645 return; 0646 #endif 0647 } 0648 extArcReady = true; 0649 } 0650 0651 // Use the external unpacker to unpack the file 0652 QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1); 0653 KrLinecountingProcess proc; 0654 if (extArcReady) { 0655 proc << getCmd << arcTempDir + "contents.cpio" << '*' + localeEncodedString(file); 0656 } else if (arcType == "arj" || arcType == "ace" || arcType == "7z") { 0657 proc << getCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash) << localeEncodedString(file); 0658 if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! 0659 proc.setStandardInputFile("/dev/ptmx"); 0660 file = url.fileName(); 0661 decompressToFile = true; 0662 } else { 0663 decompressedLen = 0; 0664 // Determine the mimetype of the file to be retrieved, and emit it. 0665 // This is mandatory in all slaves (for KRun/BrowserRun to work). 0666 QMimeDatabase db; 0667 QMimeType mt = db.mimeTypeForFile(arcTempDir + file); 0668 if (mt.isValid()) 0669 mimeType(mt.name()); 0670 0671 QString escapedFilename = file; 0672 if (arcType == "zip") // left bracket needs to be escaped 0673 escapedFilename.replace('[', "[[]"); 0674 proc << getCmd << getPath(arcFile->url()); 0675 if (arcType != "gzip" && arcType != "bzip2" && arcType != "lzma" && arcType != "xz") 0676 proc << localeEncodedString(escapedFilename); 0677 connect(&proc, &KrLinecountingProcess::newOutputData, this, &kio_krarcProtocol::receivedData); 0678 proc.setMerge(false); 0679 } 0680 infoMessage(i18n("Unpacking %1...", url.fileName())); 0681 // change the working directory to our arcTempDir 0682 QDir::setCurrent(arcTempDir); 0683 0684 SET_KRCODEC 0685 proc.setTextModeEnabled(false); 0686 proc.start(); 0687 RESET_KRCODEC 0688 0689 // Wait until the external unpacker has finished 0690 if (!proc.waitForFinished(-1)) { 0691 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0692 return WorkerResult::fail(KIO::ERR_SLAVE_DEFINED, 0693 i18n("An error has happened, related to the external program '%1'. " 0694 "The error message is: '%2'.", 0695 cmd, 0696 proc.errorString())); 0697 #else 0698 error(KIO::ERR_SLAVE_DEFINED, 0699 i18n("An error has happened, related to the external program '%1'. " 0700 "The error message is: '%2'.", 0701 cmd, 0702 proc.errorString())); 0703 return; 0704 #endif 0705 } 0706 0707 if (!extArcReady && !decompressToFile) { 0708 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode()) 0709 || (arcType != "bzip2" && arcType != "lzma" && arcType != "xz" && expectedSize != decompressedLen)) { 0710 if (encrypted && tries) { 0711 invalidatePassword(); 0712 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0713 return get(url, tries - 1); 0714 } 0715 return WorkerResult::fail(KIO::ERR_ACCESS_DENIED, getPath(url) + "\n\n" + proc.getErrorMsg()); 0716 #else 0717 get(url, tries - 1); 0718 return; 0719 } 0720 error(KIO::ERR_ACCESS_DENIED, getPath(url) + "\n\n" + proc.getErrorMsg()); 0721 return; 0722 #endif 0723 } 0724 } else { 0725 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode()) || !QFileInfo::exists(arcTempDir + file)) { 0726 if (decompressToFile) 0727 QFile(arcTempDir + file).remove(); 0728 if (encrypted && tries) { 0729 invalidatePassword(); 0730 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0731 return get(url, tries - 1); 0732 } 0733 return WorkerResult::fail(KIO::ERR_ACCESS_DENIED, getPath(url)); 0734 #else 0735 get(url, tries - 1); 0736 return; 0737 } 0738 error(KIO::ERR_ACCESS_DENIED, getPath(url)); 0739 return; 0740 #endif 0741 } 0742 // the following block is ripped from KDE file KIO::Slave 0743 // $Id: krarc.cpp,v 1.43 2007/01/13 13:39:51 ckarai Exp $ 0744 QByteArray _path(QFile::encodeName(arcTempDir + file)); 0745 QT_STATBUF buff; 0746 if (QT_LSTAT(_path.data(), &buff) == -1) { 0747 if (errno == EACCES) 0748 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0749 return WorkerResult::fail(KIO::ERR_ACCESS_DENIED, getPath(url)); 0750 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, getPath(url)); 0751 } 0752 if (S_ISDIR(buff.st_mode)) { 0753 return WorkerResult::fail(KIO::ERR_IS_DIRECTORY, getPath(url)); 0754 } 0755 if (!S_ISREG(buff.st_mode)) { 0756 return WorkerResult::fail(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url)); 0757 } 0758 int fd = QT_OPEN(_path.data(), O_RDONLY); 0759 if (fd < 0) { 0760 return WorkerResult::fail(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url)); 0761 } 0762 #else 0763 error(KIO::ERR_ACCESS_DENIED, getPath(url)); 0764 else 0765 error(KIO::ERR_DOES_NOT_EXIST, getPath(url)); 0766 return; 0767 } 0768 if (S_ISDIR(buff.st_mode)) { 0769 error(KIO::ERR_IS_DIRECTORY, getPath(url)); 0770 return; 0771 } 0772 if (!S_ISREG(buff.st_mode)) { 0773 error(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url)); 0774 return; 0775 } 0776 int fd = QT_OPEN(_path.data(), O_RDONLY); 0777 if (fd < 0) { 0778 error(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url)); 0779 return; 0780 } 0781 #endif 0782 // Determine the mimetype of the file to be retrieved, and emit it. 0783 // This is mandatory in all slaves (for KRun/BrowserRun to work). 0784 QMimeDatabase db; 0785 QMimeType mt = db.mimeTypeForFile(arcTempDir + file); 0786 if (mt.isValid()) 0787 mimeType(mt.name()); 0788 0789 KIO::filesize_t processed_size = 0; 0790 0791 QString resumeOffset = metaData("resume"); 0792 if (!resumeOffset.isEmpty()) { 0793 bool ok; 0794 KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok); 0795 if (ok && (offset > 0) && (offset < buff.st_size)) { 0796 if (QT_LSEEK(fd, offset, SEEK_SET) == offset) { 0797 canResume(); 0798 processed_size = offset; 0799 } 0800 } 0801 } 0802 0803 totalSize(buff.st_size); 0804 0805 char buffer[MAX_IPC_SIZE]; 0806 while (1) { 0807 int n = int(::read(fd, buffer, MAX_IPC_SIZE)); 0808 if (n == -1) { 0809 if (errno == EINTR) 0810 continue; 0811 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0812 ::close(fd); 0813 return WorkerResult::fail(KIO::ERR_CANNOT_READ, getPath(url)); 0814 #else 0815 error(KIO::ERR_CANNOT_READ, getPath(url)); 0816 ::close(fd); 0817 return; 0818 #endif 0819 } 0820 if (n == 0) 0821 break; // Finished 0822 0823 { 0824 QByteArray array = QByteArray::fromRawData(buffer, n); 0825 data(array); 0826 } 0827 0828 processed_size += n; 0829 } 0830 0831 data(QByteArray()); 0832 ::close(fd); 0833 processedSize(buff.st_size); 0834 0835 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0836 if (decompressToFile) 0837 QFile(arcTempDir + file).remove(); 0838 return WorkerResult::pass(); 0839 #else 0840 finished(); 0841 0842 if (decompressToFile) 0843 QFile(arcTempDir + file).remove(); 0844 return; 0845 #endif 0846 } 0847 // send empty buffer to mark EOF 0848 data(QByteArray()); 0849 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0850 return WorkerResult::pass(); 0851 #else 0852 finished(); 0853 #endif 0854 } 0855 0856 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0857 KIO::WorkerResult kio_krarcProtocol::del(QUrl const &url, bool isFile) 0858 #else 0859 void kio_krarcProtocol::del(QUrl const &url, bool isFile) 0860 #endif 0861 { 0862 KRFUNC; 0863 KRDEBUG(getPath(url)); 0864 0865 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0866 const auto writeSupportResult = checkWriteSupport(); 0867 if (!writeSupportResult.success()) 0868 return writeSupportResult; 0869 0870 const auto setArcFileResult = setArcFile(url); 0871 if (!setArcFileResult.success()) { 0872 return setArcFileResult; 0873 } 0874 if (newArchiveURL && !initDirDict(url)) { 0875 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0876 } 0877 0878 if (delCmd.isEmpty()) { 0879 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, i18n("Deleting files from %1 archives is not supported", arcType)); 0880 } 0881 if (!findFileEntry(url)) { 0882 if ((arcType != "arj" && arcType != "lha") || isFile) { 0883 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, getPath(url)); 0884 } 0885 } 0886 #else 0887 if (!checkWriteSupport()) 0888 return; 0889 0890 if (!setArcFile(url)) { 0891 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0892 return; 0893 } 0894 if (newArchiveURL && !initDirDict(url)) { 0895 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0896 return; 0897 } 0898 0899 if (delCmd.isEmpty()) { 0900 error(ERR_UNSUPPORTED_ACTION, i18n("Deleting files from %1 archives is not supported", arcType)); 0901 return; 0902 } 0903 if (!findFileEntry(url)) { 0904 if ((arcType != "arj" && arcType != "lha") || isFile) { 0905 error(KIO::ERR_DOES_NOT_EXIST, getPath(url)); 0906 return; 0907 } 0908 } 0909 #endif 0910 0911 QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1); 0912 if (!isFile && file.right(1) != DIR_SEPARATOR) { 0913 if (arcType == "zip") 0914 file = file + DIR_SEPARATOR; 0915 } 0916 KrLinecountingProcess proc; 0917 proc << delCmd << getPath(arcFile->url()) << localeEncodedString(file); 0918 infoMessage(i18n("Deleting %1...", url.fileName())); 0919 0920 SET_KRCODEC 0921 proc.start(); 0922 RESET_KRCODEC 0923 0924 proc.waitForFinished(); 0925 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { 0926 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0927 return WorkerResult::fail(ERR_CANNOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); 0928 #else 0929 error(ERR_CANNOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); 0930 return; 0931 #endif 0932 } 0933 // force a refresh of archive information 0934 initDirDict(url, true); 0935 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0936 return WorkerResult::pass(); 0937 #else 0938 finished(); 0939 #endif 0940 } 0941 0942 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0943 KIO::WorkerResult kio_krarcProtocol::stat(const QUrl &url) 0944 #else 0945 void kio_krarcProtocol::stat(const QUrl &url) 0946 #endif 0947 { 0948 KRFUNC; 0949 KRDEBUG(getPath(url)); 0950 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0951 const auto setArcFileResult = setArcFile(url); 0952 if (!setArcFileResult.success()) { 0953 return setArcFileResult; 0954 } 0955 if (newArchiveURL && !initDirDict(url)) { 0956 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0957 } 0958 0959 if (listCmd.isEmpty()) { 0960 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, i18n("Accessing files is not supported with %1 archives", arcType)); 0961 } 0962 #else 0963 if (!setArcFile(url)) { 0964 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0965 return; 0966 } 0967 if (newArchiveURL && !initDirDict(url)) { 0968 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 0969 return; 0970 } 0971 0972 if (listCmd.isEmpty()) { 0973 error(ERR_UNSUPPORTED_ACTION, i18n("Accessing files is not supported with %1 archives", arcType)); 0974 return; 0975 } 0976 #endif 0977 0978 QString path = getPath(url, QUrl::StripTrailingSlash); 0979 QUrl newUrl = url; 0980 0981 // but treat the archive itself as the archive root 0982 if (path == getPath(arcFile->url(), QUrl::StripTrailingSlash)) { 0983 newUrl.setPath(path + DIR_SEPARATOR); 0984 path = getPath(newUrl); 0985 } 0986 // we might be stating a real file 0987 if (QFileInfo::exists(path)) { 0988 QT_STATBUF buff; 0989 QT_STAT(path.toLocal8Bit(), &buff); 0990 QString mime; 0991 QMimeDatabase db; 0992 QMimeType result = db.mimeTypeForFile(path); 0993 if (result.isValid()) 0994 mime = result.name(); 0995 statEntry(KFileItem(QUrl::fromLocalFile(path), mime, buff.st_mode).entry()); 0996 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 0997 return WorkerResult::pass(); 0998 #else 0999 finished(); 1000 return; 1001 #endif 1002 } 1003 UDSEntry *entry = findFileEntry(newUrl); 1004 if (entry) { 1005 statEntry(*entry); 1006 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1007 return WorkerResult::pass(); 1008 } 1009 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, path); 1010 #else 1011 finished(); 1012 } else 1013 error(KIO::ERR_DOES_NOT_EXIST, path); 1014 #endif 1015 } 1016 1017 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1018 KIO::WorkerResult kio_krarcProtocol::copy(const QUrl &url, const QUrl &dest, int, KIO::JobFlags flags) 1019 #else 1020 void kio_krarcProtocol::copy(const QUrl &url, const QUrl &dest, int, KIO::JobFlags flags) 1021 #endif 1022 { 1023 KRDEBUG("source: " << url.path() << " dest: " << dest.path()); 1024 1025 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1026 const auto writeSupportResult = checkWriteSupport(); 1027 if (!writeSupportResult.success()) 1028 return writeSupportResult; 1029 #else 1030 if (!checkWriteSupport()) 1031 return; 1032 #endif 1033 1034 bool overwrite = !!(flags & KIO::Overwrite); 1035 1036 // KDE HACK: opening the password dlg in copy causes error for the COPY, and further problems 1037 // that's why encrypted files are not allowed to copy 1038 if (!encrypted && dest.isLocalFile()) 1039 do { 1040 if (url.fileName() != dest.fileName()) 1041 break; 1042 1043 if (QTextCodec::codecForLocale()->name() != codec->name()) 1044 break; 1045 1046 // the file exists and we don't want to overwrite 1047 if ((!overwrite) && (QFile(getPath(dest)).exists())) { 1048 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1049 return WorkerResult::fail((int)ERR_FILE_ALREADY_EXIST, QString(QFile::encodeName(getPath(dest)))); 1050 }; 1051 1052 const auto setArcFileResult = setArcFile(url); 1053 if (!setArcFileResult.success()) { 1054 return setArcFileResult; 1055 } 1056 if (newArchiveURL && !initDirDict(url)) { 1057 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1058 } 1059 #else 1060 error((int)ERR_FILE_ALREADY_EXIST, QString(QFile::encodeName(getPath(dest)))); 1061 return; 1062 }; 1063 1064 if (!setArcFile(url)) { 1065 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1066 return; 1067 } 1068 if (newArchiveURL && !initDirDict(url)) { 1069 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1070 return; 1071 } 1072 #endif 1073 1074 UDSEntry *entry = findFileEntry(url); 1075 if (copyCmd.isEmpty() || !entry) 1076 break; 1077 1078 QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1); 1079 1080 QString destDir = getPath(dest, QUrl::StripTrailingSlash); 1081 if (!QDir(destDir).exists()) { 1082 int ndx = destDir.lastIndexOf(DIR_SEPARATOR_CHAR); 1083 if (ndx != -1) 1084 destDir.truncate(ndx + 1); 1085 } 1086 1087 QDir::setCurrent(destDir); 1088 1089 QString escapedFilename = file; 1090 if (arcType == "zip") { 1091 // left bracket needs to be escaped 1092 escapedFilename.replace('[', "[[]"); 1093 } 1094 1095 KrLinecountingProcess proc; 1096 proc << copyCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash) << escapedFilename; 1097 if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! 1098 proc.setStandardInputFile("/dev/ptmx"); 1099 proc.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect 1100 1101 infoMessage(i18n("Unpacking %1...", url.fileName())); 1102 proc.start(); 1103 proc.waitForFinished(); 1104 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { 1105 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1106 return WorkerResult::fail(KIO::ERR_CANNOT_WRITE, getPath(dest, QUrl::StripTrailingSlash) + "\n\n" + proc.getErrorMsg()); 1107 #else 1108 error(KIO::ERR_CANNOT_WRITE, getPath(dest, QUrl::StripTrailingSlash) + "\n\n" + proc.getErrorMsg()); 1109 return; 1110 #endif 1111 } 1112 if (!QFileInfo::exists(getPath(dest, QUrl::StripTrailingSlash))) { 1113 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1114 return WorkerResult::fail(KIO::ERR_CANNOT_WRITE, getPath(dest, QUrl::StripTrailingSlash)); 1115 #else 1116 error(KIO::ERR_CANNOT_WRITE, getPath(dest, QUrl::StripTrailingSlash)); 1117 return; 1118 #endif 1119 } 1120 1121 processedSize(KFileItem(*entry, url).size()); 1122 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1123 QDir::setCurrent(QDir::rootPath()); /* for being able to umount devices after copying*/ 1124 return WorkerResult::pass(); 1125 #else 1126 finished(); 1127 QDir::setCurrent(QDir::rootPath()); /* for being able to umount devices after copying*/ 1128 return; 1129 #endif 1130 1131 } while (0); 1132 1133 if (encrypted) 1134 KRDEBUG("ERROR: " << url.path() << " is encrypted."); 1135 if (!dest.isLocalFile()) 1136 KRDEBUG("ERROR: " << url.path() << " is not a local file."); 1137 1138 // CMD_COPY is no more in KF5 - replaced with 74 value (as stated in https://invent.kde.org/frameworks/kio/-/blob/master/src/core/commands_p.h) 1139 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1140 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString("kio_krarc", 74)); 1141 #else 1142 error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, 74)); 1143 #endif 1144 } 1145 1146 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1147 KIO::WorkerResult kio_krarcProtocol::rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) 1148 #else 1149 void kio_krarcProtocol::rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) 1150 #endif 1151 { 1152 Q_UNUSED(flags); 1153 1154 KRDEBUG("renaming from: " << src.path() << " to: " << dest.path()); 1155 KRDEBUG("command: " << arcPath); 1156 1157 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1158 const auto writeSupportResult = checkWriteSupport(); 1159 if (!writeSupportResult.success()) 1160 return writeSupportResult; 1161 1162 if (renCmd.isEmpty()) { 1163 return WorkerResult::fail(KIO::ERR_CANNOT_RENAME, src.fileName()); 1164 } 1165 1166 if (src.fileName() == dest.fileName()) { 1167 return WorkerResult::pass(); 1168 } 1169 #else 1170 if (!checkWriteSupport()) { 1171 return; 1172 } 1173 1174 if (renCmd.isEmpty()) { 1175 error(KIO::ERR_CANNOT_RENAME, src.fileName()); 1176 return; 1177 } 1178 1179 if (src.fileName() == dest.fileName()) { 1180 return; 1181 } 1182 #endif 1183 1184 KrLinecountingProcess proc; 1185 proc << renCmd << arcPath << src.path().remove(arcPath + '/') << dest.path().remove(arcPath + '/'); 1186 proc.start(); 1187 proc.waitForFinished(); 1188 1189 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { 1190 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1191 return WorkerResult::fail(KIO::ERR_CANNOT_RENAME, src.fileName()); 1192 } 1193 1194 return WorkerResult::pass(); 1195 #else 1196 error(KIO::ERR_CANNOT_RENAME, src.fileName()); 1197 return; 1198 } 1199 1200 finished(); 1201 #endif 1202 } 1203 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1204 KIO::WorkerResult kio_krarcProtocol::listDir(const QUrl &url) 1205 #else 1206 void kio_krarcProtocol::listDir(const QUrl &url) 1207 #endif 1208 { 1209 KRFUNC; 1210 KRDEBUG(getPath(url)); 1211 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1212 const auto setArcFileResult = setArcFile(url); 1213 if (!setArcFileResult.success()) { 1214 return setArcFileResult; 1215 } 1216 if (listCmd.isEmpty()) { 1217 return WorkerResult::fail(ERR_UNSUPPORTED_ACTION, i18n("Listing folders is not supported for %1 archives", arcType)); 1218 #else 1219 if (!setArcFile(url)) { 1220 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1221 return; 1222 } 1223 if (listCmd.isEmpty()) { 1224 error(ERR_UNSUPPORTED_ACTION, i18n("Listing folders is not supported for %1 archives", arcType)); 1225 return; 1226 #endif 1227 } 1228 QString path = getPath(url); 1229 if (path.right(1) != DIR_SEPARATOR) 1230 path = path + DIR_SEPARATOR; 1231 1232 // it might be a real dir ! 1233 if (QFileInfo::exists(path)) { 1234 if (QFileInfo(path).isDir()) { 1235 QUrl redir; 1236 redir.setPath(getPath(url)); 1237 redirection(redir); 1238 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1239 return WorkerResult::pass(); 1240 } 1241 // maybe it's an archive ! 1242 return WorkerResult::fail(ERR_IS_FILE, path); 1243 } 1244 if (!initDirDict(url)) { 1245 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1246 } 1247 #else 1248 finished(); 1249 } else { // maybe it's an archive ! 1250 error(ERR_IS_FILE, path); 1251 } 1252 return; 1253 } 1254 if (!initDirDict(url)) { 1255 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1256 return; 1257 } 1258 #endif 1259 1260 QString arcDir = path.mid(getPath(arcFile->url()).length()); 1261 arcDir.truncate(arcDir.lastIndexOf(DIR_SEPARATOR)); 1262 if (arcDir.right(1) != DIR_SEPARATOR) 1263 arcDir = arcDir + DIR_SEPARATOR; 1264 1265 if (dirDict.find(arcDir) == dirDict.end()) { 1266 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1267 return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1268 #else 1269 error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); 1270 return; 1271 #endif 1272 } 1273 UDSEntryList *dirList = dirDict[arcDir]; 1274 totalSize(dirList->size()); 1275 listEntries(*dirList); 1276 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1277 return WorkerResult::pass(); 1278 #else 1279 finished(); 1280 #endif 1281 } 1282 1283 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1284 KIO::WorkerResult kio_krarcProtocol::setArcFile(const QUrl &url) 1285 #else 1286 bool kio_krarcProtocol::setArcFile(const QUrl &url) 1287 #endif 1288 { 1289 KRFUNC; 1290 KRDEBUG(url.fileName()); 1291 QString path = getPath(url); 1292 time_t currTime = time(nullptr); 1293 archiveChanged = true; 1294 newArchiveURL = true; 1295 // is the file already set ? 1296 if (arcFile && getPath(arcFile->url(), QUrl::StripTrailingSlash) == path.left(getPath(arcFile->url(), QUrl::StripTrailingSlash).length())) { 1297 newArchiveURL = false; 1298 // Has it changed ? 1299 KFileItem *newArcFile = new KFileItem(arcFile->url(), QString(), arcFile->mode()); 1300 if (metaData("Charset") != currentCharset || !newArcFile->cmp(*arcFile)) { 1301 currentCharset = metaData("Charset"); 1302 1303 codec = QTextCodec::codecForName(currentCharset.toLatin1()); 1304 if (codec == nullptr) 1305 codec = QTextCodec::codecForMib(4 /* latin-1 */); 1306 1307 delete arcFile; 1308 password.clear(); 1309 extArcReady = false; 1310 arcFile = newArcFile; 1311 } else { // same old file 1312 delete newArcFile; 1313 archiveChanged = false; 1314 if (encrypted && password.isNull()) 1315 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1316 (void)initArcParameters(); 1317 #else 1318 initArcParameters(); 1319 #endif 1320 } 1321 } else { // it's a new file... 1322 extArcReady = false; 1323 1324 // new archive file means new dirDict, too 1325 dirDict.clear(); 1326 1327 if (arcFile) { 1328 delete arcFile; 1329 password.clear(); 1330 arcFile = nullptr; 1331 } 1332 QString newPath = path; 1333 if (newPath.right(1) != DIR_SEPARATOR) 1334 newPath = newPath + DIR_SEPARATOR; 1335 for (int pos = 0; pos >= 0; pos = newPath.indexOf(DIR_SEPARATOR, pos + 1)) { 1336 QFileInfo qfi(newPath.left(pos)); 1337 if (qfi.exists() && !qfi.isDir()) { 1338 QT_STATBUF stat_p; 1339 QT_LSTAT(newPath.left(pos).toLocal8Bit(), &stat_p); 1340 arcFile = new KFileItem(QUrl::fromLocalFile(newPath.left(pos)), QString(), stat_p.st_mode); 1341 break; 1342 } 1343 } 1344 if (!arcFile) { 1345 // KRDEBUG("ERROR: " << path << " does not exist."); 1346 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1347 return WorkerResult::fail(KIO::ERR_DOES_NOT_EXIST, url.toString()); 1348 #else 1349 error(ERR_DOES_NOT_EXIST, path); 1350 return false; // file not found 1351 #endif 1352 } 1353 currentCharset = metaData("Charset"); 1354 1355 codec = QTextCodec::codecForName(currentCharset.toLatin1()); 1356 if (codec == nullptr) 1357 codec = QTextCodec::codecForMib(4 /* latin-1 */); 1358 } 1359 1360 /* FIX: file change can only be detected if the timestamp between the two consequent 1361 changes is more than 1s. If the archive is continuously changing (check: move files 1362 inside the archive), krarc may erroneously think, that the archive file is unchanged, 1363 because the timestamp is the same as the previous one. This situation can only occur 1364 if the modification time equals with the current time. While this condition is true, 1365 we can say, that the archive is changing, so content reread is always necessary 1366 during that period. */ 1367 if (archiveChanging) 1368 archiveChanged = true; 1369 archiveChanging = (currTime == (time_t)arcFile->time(KFileItem::ModificationTime).toTime_t()); 1370 1371 arcPath = getPath(arcFile->url(), QUrl::StripTrailingSlash); 1372 arcType = detectArchive(encrypted, arcPath); 1373 1374 if (arcType == "tbz") 1375 arcType = "bzip2"; 1376 else if (arcType == "tgz") 1377 arcType = "gzip"; 1378 else if (arcType == "tlz") 1379 arcType = "lzma"; 1380 else if (arcType == "txz") 1381 arcType = "xz"; 1382 1383 if (arcType.isEmpty()) { 1384 arcType = arcFile->mimetype(); 1385 arcType = getShortTypeFromMime(arcType); 1386 if (arcType == "jar") 1387 arcType = "zip"; 1388 } 1389 1390 return initArcParameters(); 1391 } 1392 1393 bool kio_krarcProtocol::initDirDict(const QUrl &url, bool forced) 1394 { 1395 KRFUNC; 1396 KRDEBUG(getPath(url)); 1397 // set the archive location 1398 // if( !setArcFile(getPath(url)) ) return false; 1399 // no need to rescan the archive if it's not changed 1400 // KRDEBUG("achiveChanged: " << archiveChanged << " forced: " << forced); 1401 if (!archiveChanged && !forced) { 1402 // KRDEBUG("doing nothing."); 1403 return true; 1404 } 1405 1406 extArcReady = false; 1407 1408 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1409 const auto setArcFileResult = setArcFile(url); 1410 if (!setArcFileResult.success()) { /* if the archive was changed refresh the file information */ 1411 return false; 1412 } 1413 #else 1414 if (!setArcFile(url)) 1415 return false; /* if the archive was changed refresh the file information */ 1416 #endif 1417 1418 // write the temp file 1419 KrLinecountingProcess proc; 1420 QTemporaryFile temp; 1421 1422 // parse the temp file 1423 if (!temp.open()) { 1424 #if KSERVICE_VERSION < QT_VERSION_CHECK(5, 96, 0) 1425 error(ERR_CANNOT_READ, temp.fileName()); 1426 #endif 1427 return false; 1428 } 1429 1430 if (arcType != "bzip2" && arcType != "lzma" && arcType != "xz") { 1431 if (arcType == "rpm") { 1432 proc << listCmd << arcPath; 1433 proc.setStandardOutputFile(temp.fileName()); 1434 } else { 1435 proc << listCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash); 1436 proc.setStandardOutputFile(temp.fileName()); 1437 } 1438 if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! 1439 proc.setStandardInputFile("/dev/ptmx"); 1440 1441 proc.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect 1442 proc.start(); 1443 proc.waitForFinished(); 1444 if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) 1445 return false; 1446 } 1447 // clear the dir dictionary 1448 1449 QHashIterator<QString, KIO::UDSEntryList *> lit(dirDict); 1450 while (lit.hasNext()) 1451 delete lit.next().value(); 1452 dirDict.clear(); 1453 1454 // add the "/" directory 1455 auto *root = new UDSEntryList(); 1456 dirDict.insert(DIR_SEPARATOR, root); 1457 // and the "/" UDSEntry 1458 UDSEntry entry; 1459 entry.fastInsert(KIO::UDSEntry::UDS_NAME, "."); 1460 mode_t mode = parsePermString("drwxr-xr-x"); 1461 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only 1462 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only 1463 1464 root->append(entry); 1465 1466 if (arcType == "bzip2" || arcType == "lzma" || arcType == "xz") 1467 abort(); 1468 1469 char buf[1000]; 1470 QString line; 1471 1472 int lineNo = 0; 1473 bool invalidLine = false; 1474 // the rar list is started with a ------ line. 1475 if (arcType == "rar" || arcType == "arj" || arcType == "lha" || arcType == "7z") { 1476 while (temp.readLine(buf, 1000) != -1) { 1477 line = decodeString(buf); 1478 if (line.startsWith(QLatin1String("----------"))) 1479 break; 1480 } 1481 } 1482 while (temp.readLine(buf, 1000) != -1) { 1483 line = decodeString(buf); 1484 if (arcType == "rar") { 1485 // the rar list is ended with a ------ line. 1486 if (line.startsWith(QLatin1String("----------"))) { 1487 invalidLine = !invalidLine; 1488 break; 1489 } 1490 if (invalidLine) 1491 continue; 1492 else { 1493 if (line[0] == '*') // encrypted archives starts with '*' 1494 line[0] = ' '; 1495 } 1496 } 1497 if (arcType == "ace") { 1498 // the ace list begins with a number. 1499 if (!line[0].isDigit()) 1500 continue; 1501 } 1502 if (arcType == "arj") { 1503 // the arj list is ended with a ------ line. 1504 if (line.startsWith(QLatin1String("----------"))) { 1505 invalidLine = !invalidLine; 1506 continue; 1507 } 1508 if (invalidLine) 1509 continue; 1510 else { 1511 temp.readLine(buf, 1000); 1512 line = line + decodeString(buf); 1513 temp.readLine(buf, 1000); 1514 line = line + decodeString(buf); 1515 temp.readLine(buf, 1000); 1516 line = line + decodeString(buf); 1517 } 1518 } 1519 if (arcType == "lha" || arcType == "7z") { 1520 // the arj list is ended with a ------ line. 1521 if (line.startsWith(QLatin1String("----------"))) 1522 break; 1523 } 1524 parseLine(lineNo++, line.trimmed()); 1525 } 1526 // close and delete our file 1527 temp.close(); 1528 1529 archiveChanged = false; 1530 // KRDEBUG("done."); 1531 return true; 1532 } 1533 1534 QString kio_krarcProtocol::findArcDirectory(const QUrl &url) 1535 { 1536 KRFUNC; 1537 KRDEBUG(url.fileName()); 1538 1539 QString path = getPath(url); 1540 if (path.right(1) == DIR_SEPARATOR) 1541 path.truncate(path.length() - 1); 1542 1543 if (!initDirDict(url)) { 1544 return QString(); 1545 } 1546 QString arcDir = path.mid(getPath(arcFile->url()).length()); 1547 arcDir.truncate(arcDir.lastIndexOf(DIR_SEPARATOR)); 1548 if (arcDir.right(1) != DIR_SEPARATOR) 1549 arcDir = arcDir + DIR_SEPARATOR; 1550 1551 return arcDir; 1552 } 1553 1554 UDSEntry *kio_krarcProtocol::findFileEntry(const QUrl &url) 1555 { 1556 KRFUNC; 1557 QString arcDir = findArcDirectory(url); 1558 if (arcDir.isEmpty()) 1559 return nullptr; 1560 1561 QHash<QString, KIO::UDSEntryList *>::iterator itef = dirDict.find(arcDir); 1562 if (itef == dirDict.end()) 1563 return nullptr; 1564 UDSEntryList *dirList = itef.value(); 1565 1566 QString name = getPath(url); 1567 if (getPath(arcFile->url(), QUrl::StripTrailingSlash) == getPath(url, QUrl::StripTrailingSlash)) 1568 name = '.'; // the '/' case 1569 else { 1570 if (name.right(1) == DIR_SEPARATOR) 1571 name.truncate(name.length() - 1); 1572 name = name.mid(name.lastIndexOf(DIR_SEPARATOR) + 1); 1573 } 1574 1575 UDSEntryList::iterator entry; 1576 1577 for (entry = dirList->begin(); entry != dirList->end(); ++entry) { 1578 if ((entry->contains(KIO::UDSEntry::UDS_NAME)) && (entry->stringValue(KIO::UDSEntry::UDS_NAME) == name)) 1579 return &(*entry); 1580 } 1581 return nullptr; 1582 } 1583 1584 QString kio_krarcProtocol::nextWord(QString &s, char d) 1585 { 1586 // Note: KRFUNC was not used here in order to avoid filling the log with too much information 1587 s = s.trimmed(); 1588 int j = s.indexOf(d, 0); 1589 QString temp = s.left(j); // find the leftmost word. 1590 s.remove(0, j); 1591 return temp; 1592 } 1593 1594 mode_t kio_krarcProtocol::parsePermString(QString perm) 1595 { 1596 KRFUNC; 1597 mode_t mode = 0; 1598 // file type 1599 if (perm[0] == 'd') 1600 mode |= S_IFDIR; 1601 #ifndef Q_OS_WIN 1602 if (perm[0] == 'l') 1603 mode |= S_IFLNK; 1604 #endif 1605 if (perm[0] == '-') 1606 mode |= S_IFREG; 1607 // owner permissions 1608 if (perm[1] != '-') 1609 mode |= S_IRUSR; 1610 if (perm[2] != '-') 1611 mode |= S_IWUSR; 1612 if (perm[3] != '-') 1613 mode |= S_IXUSR; 1614 #ifndef Q_OS_WIN 1615 // group permissions 1616 if (perm[4] != '-') 1617 mode |= S_IRGRP; 1618 if (perm[5] != '-') 1619 mode |= S_IWGRP; 1620 if (perm[6] != '-') 1621 mode |= S_IXGRP; 1622 // other permissions 1623 if (perm[7] != '-') 1624 mode |= S_IROTH; 1625 if (perm[8] != '-') 1626 mode |= S_IWOTH; 1627 if (perm[9] != '-') 1628 mode |= S_IXOTH; 1629 #endif 1630 return mode; 1631 } 1632 1633 UDSEntryList *kio_krarcProtocol::addNewDir(const QString &path) 1634 { 1635 KRFUNC; 1636 UDSEntryList *dir; 1637 1638 // check if the current dir exists 1639 QHash<QString, KIO::UDSEntryList *>::iterator itef = dirDict.find(path); 1640 if (itef != dirDict.end()) 1641 return itef.value(); 1642 1643 // set dir to the parent dir 1644 dir = addNewDir(path.left(path.lastIndexOf(DIR_SEPARATOR, -2) + 1)); 1645 1646 // add a new entry in the parent dir 1647 QString name = path.mid(path.lastIndexOf(DIR_SEPARATOR, -2) + 1); 1648 name = name.left(name.length() - 1); 1649 1650 if (name == "." || name == "..") { // entries with these names wouldn't be displayed 1651 // don't translate since this is an internal error 1652 QString err = QString("Cannot handle path: ") + path; 1653 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 1654 KRDEBUG("ERROR: " << err); 1655 #else 1656 // KRDEBUG("ERROR: " << err); 1657 error(KIO::ERR_INTERNAL, err); 1658 #endif 1659 exit(); 1660 } 1661 1662 UDSEntry entry; 1663 entry.fastInsert(KIO::UDSEntry::UDS_NAME, name); 1664 mode_t mode = parsePermString("drwxr-xr-x"); 1665 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only 1666 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only 1667 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, 0); 1668 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, arcFile->time(KFileItem::ModificationTime).toTime_t()); 1669 1670 dir->append(entry); 1671 1672 // create a new directory entry and add it.. 1673 dir = new UDSEntryList(); 1674 dirDict.insert(path, dir); 1675 1676 return dir; 1677 } 1678 1679 void kio_krarcProtocol::parseLine(int lineNo, QString line) 1680 { 1681 KRFUNC; 1682 UDSEntryList *dir; 1683 UDSEntry entry; 1684 1685 QString owner; 1686 QString group; 1687 QString symlinkDest; 1688 QString perm; 1689 mode_t mode = 0666; 1690 size_t size = 0; 1691 time_t time = ::time(nullptr); 1692 QString fullName; 1693 1694 if (arcType == "zip") { 1695 // permissions 1696 perm = nextWord(line); 1697 // ignore the next 2 fields 1698 nextWord(line); 1699 nextWord(line); 1700 // size 1701 size = nextWord(line).toLong(); 1702 // ignore the next 2 fields 1703 nextWord(line); 1704 nextWord(line); 1705 // date & time 1706 QString d = nextWord(line); 1707 QDate qdate(d.mid(0, 4).toInt(), d.mid(4, 2).toInt(), d.mid(6, 2).toInt()); 1708 QTime qtime(d.mid(9, 2).toInt(), d.mid(11, 2).toInt(), d.mid(13, 2).toInt()); 1709 time = QDateTime(qdate, qtime).toTime_t(); 1710 // full name 1711 fullName = nextWord(line, '\n'); 1712 1713 if (perm.length() != 10) 1714 perm = (perm.at(0) == 'd' || fullName.endsWith(DIR_SEPARATOR)) ? "drwxr-xr-x" : "-rw-r--r--"; 1715 mode = parsePermString(perm); 1716 } 1717 if (arcType == "rar") { 1718 // permissions 1719 perm = nextWord(line); 1720 // size 1721 size = nextWord(line).toLong(); 1722 // ignore the next 2 fields : packed size and compression ration 1723 nextWord(line); 1724 nextWord(line); 1725 // date & time 1726 QString d = nextWord(line); 1727 QDate qdate(d.left(4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt()); 1728 QString t = nextWord(line); 1729 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); 1730 time = QDateTime(qdate, qtime).toTime_t(); 1731 // checksum : ignored 1732 nextWord(line); 1733 // full name 1734 fullName = nextWord(line, '\n'); 1735 1736 if (perm.length() == 7) { // windows rar permission format 1737 bool isDir = (perm.at(1).toLower() == 'd'); 1738 bool isReadOnly = (perm.at(2).toLower() == 'r'); 1739 1740 perm = isDir ? "drwxr-xr-x" : "-rw-r--r--"; 1741 1742 if (isReadOnly) 1743 perm[2] = '-'; 1744 } 1745 1746 if (perm.length() != 10) 1747 perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--"; 1748 mode = parsePermString(perm); 1749 } 1750 if (arcType == "arj") { 1751 nextWord(line); 1752 // full name 1753 fullName = nextWord(line, '\n'); 1754 // ignore the next 2 fields 1755 nextWord(line); 1756 nextWord(line); 1757 // size 1758 size = nextWord(line).toLong(); 1759 // ignore the next 2 fields 1760 nextWord(line); 1761 nextWord(line); 1762 // date & time 1763 QString d = nextWord(line); 1764 int year = 1900 + d.mid(0, 2).toInt(); 1765 if (year < 1930) 1766 year += 100; 1767 QDate qdate(year, d.mid(3, 2).toInt(), d.mid(6, 2).toInt()); 1768 QString t = nextWord(line); 1769 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); 1770 time = QDateTime(qdate, qtime).toTime_t(); 1771 // permissions 1772 perm = nextWord(line); 1773 if (perm.length() != 10) 1774 perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--"; 1775 mode = parsePermString(perm); 1776 } 1777 if (arcType == "rpm") { 1778 // full name 1779 fullName = nextWord(line); 1780 // size 1781 size = nextWord(line).toULong(); 1782 // date & time 1783 time = nextWord(line).toULong(); 1784 // next field is md5sum, ignore it 1785 nextWord(line); 1786 // permissions 1787 mode = nextWord(line).toUInt(nullptr, 8); 1788 // Owner & Group 1789 owner = nextWord(line); 1790 group = nextWord(line); 1791 // symlink destination 1792 #ifndef Q_OS_WIN 1793 if (S_ISLNK(mode)) { 1794 // ignore the next 3 fields 1795 nextWord(line); 1796 nextWord(line); 1797 nextWord(line); 1798 symlinkDest = nextWord(line); 1799 } 1800 #endif 1801 } 1802 if (arcType == "gzip") { 1803 if (!lineNo) 1804 return; // ignore the first line 1805 // first field is uncompressed size - ignore it 1806 nextWord(line); 1807 // size 1808 size = nextWord(line).toULong(); 1809 // ignore the next field 1810 nextWord(line); 1811 // full name 1812 fullName = nextWord(line); 1813 fullName = fullName.mid(fullName.lastIndexOf(DIR_SEPARATOR) + 1); 1814 } 1815 if (arcType == "lzma") { 1816 fullName = arcFile->name(); 1817 if (fullName.endsWith(QLatin1String("lzma"))) { 1818 fullName.truncate(fullName.length() - 5); 1819 } 1820 mode = arcFile->mode(); 1821 size = arcFile->size(); 1822 } 1823 if (arcType == "xz") { 1824 fullName = arcFile->name(); 1825 if (fullName.endsWith(QLatin1String("xz"))) { 1826 fullName.truncate(fullName.length() - 3); 1827 } 1828 mode = arcFile->mode(); 1829 size = arcFile->size(); 1830 } 1831 if (arcType == "bzip2") { 1832 // There is no way to list bzip2 files, so we take our information from 1833 // the archive itself... 1834 fullName = arcFile->name(); 1835 if (fullName.endsWith(QLatin1String("bz2"))) { 1836 fullName.truncate(fullName.length() - 4); 1837 } 1838 mode = arcFile->mode(); 1839 size = arcFile->size(); 1840 } 1841 if (arcType == "lha") { 1842 // permissions 1843 perm = nextWord(line); 1844 if (perm.length() != 10) 1845 perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--"; 1846 mode = parsePermString(perm); 1847 // ignore the next field 1848 nextWord(line); 1849 // size 1850 size = nextWord(line).toLong(); 1851 // ignore the next field 1852 nextWord(line); 1853 // date & time 1854 int month = (QString("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec").split(',')).indexOf(nextWord(line)) + 1; 1855 int day = nextWord(line).toInt(); 1856 int year = QDate::currentDate().year(); 1857 QString third = nextWord(line); 1858 QTime qtime; 1859 1860 if (third.contains(":")) 1861 qtime = QTime::fromString(third); 1862 else 1863 year = third.toInt(); 1864 1865 QDate qdate(year, month, day); 1866 1867 time = QDateTime(qdate, qtime).toTime_t(); 1868 // full name 1869 fullName = nextWord(line, '\n'); 1870 } 1871 if (arcType == "ace") { 1872 // date & time 1873 QString d = nextWord(line); 1874 int year = 1900 + d.mid(6, 2).toInt(); 1875 if (year < 1930) 1876 year += 100; 1877 QDate qdate(year, d.mid(3, 2).toInt(), d.mid(0, 2).toInt()); 1878 QString t = nextWord(line); 1879 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); 1880 time = QDateTime(qdate, qtime).toTime_t(); 1881 // ignore the next field 1882 nextWord(line); 1883 // size 1884 size = nextWord(line).toLong(); 1885 // ignore the next field 1886 nextWord(line); 1887 // full name 1888 fullName = nextWord(line, '\n'); 1889 if (fullName[0] == '*') // encrypted archives starts with '*' 1890 fullName = fullName.mid(1); 1891 } 1892 if (arcType == "deb") { 1893 // permissions 1894 perm = nextWord(line); 1895 mode = parsePermString(perm); 1896 // Owner & Group 1897 owner = nextWord(line, DIR_SEPARATOR_CHAR); 1898 group = nextWord(line).mid(1); 1899 // size 1900 size = nextWord(line).toLong(); 1901 // date & time 1902 QString d = nextWord(line); 1903 QDate qdate(d.mid(0, 4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt()); 1904 QString t = nextWord(line); 1905 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); 1906 time = QDateTime(qdate, qtime).toTime_t(); 1907 // full name 1908 fullName = nextWord(line, '\n').mid(1); 1909 // if ( fullName.right( 1 ) == "/" ) return; 1910 if (fullName.contains("->")) { 1911 symlinkDest = fullName.mid(fullName.indexOf("->") + 2); 1912 fullName = fullName.left(fullName.indexOf("->") - 1); 1913 } 1914 } 1915 if (arcType == "7z") { 1916 // date & time 1917 QString d = nextWord(line); 1918 QDate qdate(d.mid(0, 4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt()); 1919 QString t = nextWord(line); 1920 QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), t.mid(6, 2).toInt()); 1921 time = QDateTime(qdate, qtime).toTime_t(); 1922 1923 // permissions 1924 perm = nextWord(line); 1925 bool isDir = (perm.at(0).toLower() == 'd'); 1926 bool isReadOnly = (perm.at(1).toLower() == 'r'); 1927 perm = isDir ? "drwxr-xr-x" : "-rw-r--r--"; 1928 if (isReadOnly) 1929 perm[2] = '-'; 1930 1931 mode = parsePermString(perm); 1932 1933 // size 1934 size = nextWord(line).toLong(); 1935 1936 // ignore the next 15 characters 1937 line = line.mid(15); 1938 1939 // full name 1940 fullName = nextWord(line, '\n'); 1941 } 1942 1943 if (fullName.right(1) == DIR_SEPARATOR) 1944 fullName = fullName.left(fullName.length() - 1); 1945 if (!fullName.startsWith(DIR_SEPARATOR)) 1946 fullName = DIR_SEPARATOR + fullName; 1947 QString path = fullName.left(fullName.lastIndexOf(DIR_SEPARATOR) + 1); 1948 // set/create the directory UDSEntryList 1949 QHash<QString, KIO::UDSEntryList *>::iterator itef = dirDict.find(path); 1950 if (itef == dirDict.end()) 1951 dir = addNewDir(path); 1952 else 1953 dir = itef.value(); 1954 1955 QString name = fullName.mid(fullName.lastIndexOf(DIR_SEPARATOR) + 1); 1956 // file name 1957 entry.fastInsert(KIO::UDSEntry::UDS_NAME, name); 1958 // file type 1959 entry.fastInsert(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only 1960 // file permissions 1961 entry.fastInsert(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only 1962 // file size 1963 entry.fastInsert(KIO::UDSEntry::UDS_SIZE, size); 1964 // modification time 1965 entry.fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, time); 1966 // link destination 1967 if (!symlinkDest.isEmpty()) { 1968 entry.fastInsert(KIO::UDSEntry::UDS_LINK_DEST, symlinkDest); 1969 } 1970 if (S_ISDIR(mode)) { 1971 fullName = fullName + DIR_SEPARATOR; 1972 if (dirDict.find(fullName) == dirDict.end()) 1973 dirDict.insert(fullName, new UDSEntryList()); 1974 else { 1975 // try to overwrite an existing entry 1976 UDSEntryList::iterator entryIt; 1977 1978 for (entryIt = dir->begin(); entryIt != dir->end(); ++entryIt) { 1979 if (entryIt->contains(KIO::UDSEntry::UDS_NAME) && entryIt->stringValue(KIO::UDSEntry::UDS_NAME) == name) { 1980 entryIt->fastInsert(KIO::UDSEntry::UDS_MODIFICATION_TIME, time); 1981 entryIt->fastInsert(KIO::UDSEntry::UDS_ACCESS, mode); 1982 return; 1983 } 1984 } 1985 return; // there is already an entry for this directory 1986 } 1987 } 1988 1989 // multi volume archives can add a file twice, use only one 1990 UDSEntryList::iterator dirEntryIt; 1991 1992 for (dirEntryIt = dir->begin(); dirEntryIt != dir->end(); ++dirEntryIt) 1993 if (dirEntryIt->contains(KIO::UDSEntry::UDS_NAME) && dirEntryIt->stringValue(KIO::UDSEntry::UDS_NAME) == name) 1994 return; 1995 1996 dir->append(entry); 1997 } 1998 1999 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 2000 KIO::WorkerResult kio_krarcProtocol::initArcParameters() 2001 #else 2002 bool kio_krarcProtocol::initArcParameters() 2003 #endif 2004 { 2005 KRFUNC; 2006 KRDEBUG("arcType: " << arcType); 2007 2008 noencoding = false; 2009 2010 cmd.clear(); 2011 listCmd = QStringList(); 2012 getCmd = QStringList(); 2013 copyCmd = QStringList(); 2014 delCmd = QStringList(); 2015 putCmd = QStringList(); 2016 renCmd = QStringList(); 2017 2018 if (arcType == "zip") { 2019 noencoding = true; 2020 cmd = fullPathName("unzip"); 2021 listCmd << fullPathName("unzip") << "-ZTs-z-t-h"; 2022 getCmd << fullPathName("unzip") << "-p"; 2023 copyCmd << fullPathName("unzip") << "-jo"; 2024 2025 if (QStandardPaths::findExecutable(QStringLiteral("zip")).isEmpty()) { 2026 delCmd = QStringList(); 2027 putCmd = QStringList(); 2028 } else { 2029 delCmd << fullPathName("zip") << "-d"; 2030 putCmd << fullPathName("zip") << "-ry"; 2031 } 2032 2033 QString a7zExecutable = find7zExecutable(); 2034 if (!a7zExecutable.isEmpty()) { 2035 renCmd << a7zExecutable << "rn"; 2036 } 2037 2038 if (!getPassword().isEmpty()) { 2039 getCmd << "-P" << password; 2040 copyCmd << "-P" << password; 2041 putCmd << "-P" << password; 2042 } 2043 } else if (arcType == "rar") { 2044 noencoding = true; 2045 if (QStandardPaths::findExecutable(QStringLiteral("rar")).isEmpty()) { 2046 cmd = fullPathName("unrar"); 2047 listCmd << fullPathName("unrar") << "-c-" 2048 << "-v" 2049 << "v"; 2050 getCmd << fullPathName("unrar") << "p" 2051 << "-ierr" 2052 << "-idp" 2053 << "-c-" 2054 << "-y"; 2055 copyCmd << fullPathName("unrar") << "e" 2056 << "-y"; 2057 delCmd = QStringList(); 2058 putCmd = QStringList(); 2059 } else { 2060 cmd = fullPathName("rar"); 2061 listCmd << fullPathName("rar") << "-c-" 2062 << "-v" 2063 << "v"; 2064 getCmd << fullPathName("rar") << "p" 2065 << "-ierr" 2066 << "-idp" 2067 << "-c-" 2068 << "-y"; 2069 copyCmd << fullPathName("rar") << "e" 2070 << "-y"; 2071 delCmd << fullPathName("rar") << "d"; 2072 putCmd << fullPathName("rar") << "-r" 2073 << "a"; 2074 } 2075 if (!getPassword().isEmpty()) { 2076 getCmd << QString("-p%1").arg(password); 2077 listCmd << QString("-p%1").arg(password); 2078 copyCmd << QString("-p%1").arg(password); 2079 if (!putCmd.isEmpty()) { 2080 putCmd << QString("-p%1").arg(password); 2081 delCmd << QString("-p%1").arg(password); 2082 } 2083 } 2084 } else if (arcType == "rpm") { 2085 cmd = fullPathName("rpm"); 2086 listCmd << fullPathName("rpm") << "--dump" 2087 << "-lpq"; 2088 getCmd << fullPathName("cpio") << "--force-local" 2089 << "--no-absolute-filenames" 2090 << "-iuvdF"; 2091 delCmd = QStringList(); 2092 putCmd = QStringList(); 2093 copyCmd = QStringList(); 2094 } else if (arcType == "gzip") { 2095 cmd = fullPathName("gzip"); 2096 listCmd << fullPathName("gzip") << "-l"; 2097 getCmd << fullPathName("gzip") << "-dc"; 2098 copyCmd = QStringList(); 2099 delCmd = QStringList(); 2100 putCmd = QStringList(); 2101 } else if (arcType == "bzip2") { 2102 cmd = fullPathName("bzip2"); 2103 listCmd << fullPathName("bzip2"); 2104 getCmd << fullPathName("bzip2") << "-dc"; 2105 copyCmd = QStringList(); 2106 delCmd = QStringList(); 2107 putCmd = QStringList(); 2108 } else if (arcType == "lzma") { 2109 cmd = fullPathName("lzma"); 2110 listCmd << fullPathName("lzma"); 2111 getCmd << fullPathName("lzma") << "-dc"; 2112 copyCmd = QStringList(); 2113 delCmd = QStringList(); 2114 putCmd = QStringList(); 2115 } else if (arcType == "xz") { 2116 cmd = fullPathName("xz"); 2117 listCmd << fullPathName("xz"); 2118 getCmd << fullPathName("xz") << "-dc"; 2119 copyCmd = QStringList(); 2120 delCmd = QStringList(); 2121 putCmd = QStringList(); 2122 } else if (arcType == "arj") { 2123 cmd = fullPathName("arj"); 2124 listCmd << fullPathName("arj") << "v" 2125 << "-y" 2126 << "-v"; 2127 getCmd << fullPathName("arj") << "-jyov" 2128 << "-v" 2129 << "e"; 2130 copyCmd << fullPathName("arj") << "-jyov" 2131 << "-v" 2132 << "e"; 2133 delCmd << fullPathName("arj") << "d"; 2134 putCmd << fullPathName("arj") << "-r" 2135 << "a"; 2136 if (!getPassword().isEmpty()) { 2137 getCmd << QString("-g%1").arg(password); 2138 copyCmd << QString("-g%1").arg(password); 2139 putCmd << QString("-g%1").arg(password); 2140 } 2141 } else if (arcType == "lha") { 2142 cmd = fullPathName("lha"); 2143 listCmd << fullPathName("lha") << "l"; 2144 getCmd << fullPathName("lha") << "pq"; 2145 copyCmd << fullPathName("lha") << "eif"; 2146 delCmd << fullPathName("lha") << "d"; 2147 putCmd << fullPathName("lha") << "a"; 2148 } else if (arcType == "ace") { 2149 cmd = fullPathName("unace"); 2150 listCmd << fullPathName("unace") << "v"; 2151 getCmd << fullPathName("unace") << "e" 2152 << "-o"; 2153 copyCmd << fullPathName("unace") << "e" 2154 << "-o"; 2155 delCmd = QStringList(); 2156 putCmd = QStringList(); 2157 if (!getPassword().isEmpty()) { 2158 getCmd << QString("-p%1").arg(password); 2159 copyCmd << QString("-p%1").arg(password); 2160 } 2161 } else if (arcType == "deb") { 2162 cmd = fullPathName("dpkg"); 2163 listCmd << fullPathName("dpkg") << "-c"; 2164 getCmd << fullPathName("tar") << "xvf"; 2165 copyCmd = QStringList(); 2166 delCmd = QStringList(); 2167 putCmd = QStringList(); 2168 } else if (arcType == "7z") { 2169 noencoding = true; 2170 cmd = find7zExecutable(); 2171 if (cmd.isEmpty()) { 2172 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 2173 return WorkerResult::fail(KIO::ERR_CANNOT_LAUNCH_PROCESS, {}); 2174 #else 2175 return false; 2176 #endif 2177 } 2178 2179 listCmd << cmd << "l" 2180 << "-y"; 2181 getCmd << cmd << "e" 2182 << "-y"; 2183 copyCmd << cmd << "e" 2184 << "-y"; 2185 delCmd << cmd << "d" 2186 << "-y"; 2187 putCmd << cmd << "a" 2188 << "-y"; 2189 renCmd << cmd << "rn"; 2190 if (!getPassword().isEmpty()) { 2191 getCmd << QString("-p%1").arg(password); 2192 listCmd << QString("-p%1").arg(password); 2193 copyCmd << QString("-p%1").arg(password); 2194 if (!putCmd.isEmpty()) { 2195 putCmd << QString("-p%1").arg(password); 2196 delCmd << QString("-p%1").arg(password); 2197 } 2198 } 2199 } 2200 // checking if it's an absolute path 2201 #ifdef Q_OS_WIN 2202 if (cmd.length() > 2 && cmd[0].isLetter() && cmd[1] == ':') 2203 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 2204 return WorkerResult::pass(); 2205 #else 2206 return true; 2207 #endif 2208 2209 #else 2210 if (cmd.startsWith(DIR_SEPARATOR)) 2211 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 2212 return WorkerResult::pass(); 2213 #else 2214 return true; 2215 #endif 2216 2217 #endif 2218 if (QStandardPaths::findExecutable(cmd).isEmpty()) { 2219 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 2220 KRDEBUG("Failed to find cmd: " << cmd); 2221 return WorkerResult::fail(KIO::ERR_CANNOT_LAUNCH_PROCESS, cmd + i18n("\nMake sure that the %1 binary is installed properly on your system.", cmd)); 2222 } 2223 return WorkerResult::pass(); 2224 #else 2225 error(KIO::ERR_CANNOT_LAUNCH_PROCESS, cmd + i18n("\nMake sure that the %1 binary is installed properly on your system.", cmd)); 2226 KRDEBUG("Failed to find cmd: " << cmd); 2227 return false; 2228 } 2229 return true; 2230 #endif 2231 } 2232 2233 bool kio_krarcProtocol::checkStatus(int exitCode) 2234 { 2235 KRFUNC; 2236 KRDEBUG(exitCode); 2237 return KrArcBaseManager::checkStatus(arcType, exitCode); 2238 } 2239 2240 void kio_krarcProtocol::checkIf7zIsEncrypted(bool &encrypted, QString fileName) 2241 { 2242 // Reminder: If that function is modified, it's important to research if the 2243 // changes must also be applied to `KrArcHandler::checkIf7zIsEncrypted()` 2244 2245 KRFUNC; 2246 if (encryptedArchPath == fileName) 2247 encrypted = true; 2248 else { // we try to find whether the 7z archive is encrypted 2249 // this is hard as the headers are also compressed 2250 QString a7zExecutable = find7zExecutable(); 2251 if (a7zExecutable.isEmpty()) { 2252 return; 2253 } 2254 2255 lastData = encryptedArchPath = ""; 2256 2257 KrLinecountingProcess proc; 2258 // Note: That command uses information given in a comment from 2259 // https://stackoverflow.com/questions/5248572/how-do-i-know-if-7zip-used-aes256 2260 proc << a7zExecutable << "l" 2261 << "-slt" << fileName; 2262 connect(&proc, &KrLinecountingProcess::newOutputData, this, &kio_krarcProtocol::check7zOutputForPassword); 2263 proc.start(); 2264 proc.waitForFinished(); 2265 encrypted = this->encrypted; 2266 2267 if (encrypted) 2268 encryptedArchPath = fileName; 2269 } 2270 } 2271 2272 void kio_krarcProtocol::check7zOutputForPassword(KProcess *proc, QByteArray &buf) 2273 { 2274 // Reminder: If that function is modified, it's important to research if the 2275 // changes must also be applied to `Kr7zEncryptionChecker::receivedOutput()` 2276 2277 KRFUNC; 2278 QString data = QString(buf); 2279 2280 QString checkable = lastData + data; 2281 2282 QStringList lines = checkable.split('\n'); 2283 lastData = lines[lines.count() - 1]; 2284 for (int i = 0; i != lines.count(); i++) { 2285 QString line = lines[i].trimmed().toLower(); 2286 int ndx = line.indexOf("listing"); // Reminder: Lower-case letters are used 2287 if (ndx >= 0) 2288 line.truncate(ndx); 2289 if (line.isEmpty()) 2290 continue; 2291 2292 if ((line.contains("password") && line.contains("enter")) || line == QStringLiteral("encrypted = +")) { 2293 KRDEBUG("Encrypted 7z archive found!"); 2294 encrypted = true; 2295 proc->kill(); 2296 return; 2297 } 2298 } 2299 } 2300 2301 void kio_krarcProtocol::invalidatePassword() 2302 { 2303 KRFUNC; 2304 KRDEBUG(getPath(arcFile->url(), QUrl::StripTrailingSlash) + DIR_SEPARATOR); 2305 2306 if (!encrypted) 2307 return; 2308 2309 KIO::AuthInfo authInfo; 2310 authInfo.caption = i18n("Krarc Password Dialog"); 2311 authInfo.username = "archive"; 2312 authInfo.readOnly = true; 2313 authInfo.keepPassword = true; 2314 authInfo.verifyPath = true; 2315 QString fileName = getPath(arcFile->url(), QUrl::StripTrailingSlash); 2316 authInfo.url = QUrl::fromLocalFile(ROOT_DIR); 2317 authInfo.url.setHost(fileName /*.replace('/','_')*/); 2318 authInfo.url.setScheme("krarc"); 2319 2320 password.clear(); 2321 2322 cacheAuthentication(authInfo); 2323 } 2324 2325 QString kio_krarcProtocol::getPassword() 2326 { 2327 KRFUNC; 2328 KRDEBUG("Encrypted: " << encrypted); 2329 2330 if (!password.isNull()) 2331 return password; 2332 if (!encrypted) 2333 return (password = ""); 2334 2335 KIO::AuthInfo authInfo; 2336 authInfo.caption = i18n("Krarc Password Dialog"); 2337 authInfo.username = "archive"; 2338 authInfo.readOnly = true; 2339 authInfo.keepPassword = true; 2340 authInfo.verifyPath = true; 2341 QString fileName = getPath(arcFile->url(), QUrl::StripTrailingSlash); 2342 authInfo.url = QUrl::fromLocalFile(ROOT_DIR); 2343 authInfo.url.setHost(fileName /*.replace('/','_')*/); 2344 authInfo.url.setScheme("krarc"); 2345 2346 if (checkCachedAuthentication(authInfo) && !authInfo.password.isNull()) { 2347 KRDEBUG(authInfo.password); 2348 return (password = authInfo.password); 2349 } 2350 2351 authInfo.password.clear(); 2352 2353 #if KSERVICE_VERSION >= QT_VERSION_CHECK(5, 96, 0) 2354 int errCode = openPasswordDialog(authInfo, i18n("Accessing the file requires a password.")); 2355 if (!errCode && !authInfo.password.isNull()) { 2356 KRDEBUG(authInfo.password); 2357 return (password = authInfo.password); 2358 } else { 2359 password.clear(); 2360 } 2361 #else 2362 2363 #if KIO_VERSION_MINOR >= 24 2364 int errCode = openPasswordDialogV2(authInfo, i18n("Accessing the file requires a password.")); 2365 if (!errCode && !authInfo.password.isNull()) { 2366 #else 2367 if (openPasswordDialog(authInfo, i18n("Accessing the file requires a password.")) && !authInfo.password.isNull()) { 2368 #endif 2369 KRDEBUG(authInfo.password); 2370 return (password = authInfo.password); 2371 #if KIO_VERSION_MINOR >= 24 2372 } else { 2373 error(errCode, QString()); 2374 #endif 2375 } 2376 2377 #endif 2378 2379 KRDEBUG(password); 2380 return password; 2381 } 2382 2383 QString kio_krarcProtocol::localeEncodedString(QString str) 2384 { 2385 // Note: KRFUNC was not used here in order to avoid filling the log with too much information 2386 if (noencoding) 2387 return str; 2388 2389 QByteArray array = codec->fromUnicode(str); 2390 2391 // encoding the byte array to QString, mapping 0x0000-0x00FF to 0xE000-0xE0FF 2392 // see KrArcCodec for more explanation 2393 int size = array.size(); 2394 QString result; 2395 2396 const char *data = array.data(); 2397 for (int i = 0; i != size; i++) { 2398 unsigned int ch = (((int)data[i]) & 0xFF) + 0xE000; // user defined character 2399 result.append(QChar(ch)); 2400 } 2401 return result; 2402 } 2403 2404 QByteArray kio_krarcProtocol::encodeString(const QString &str) 2405 { 2406 // Note: KRFUNC was not used here in order to avoid filling the log with too much information 2407 if (noencoding) 2408 return QTextCodec::codecForLocale()->fromUnicode(str); 2409 return codec->fromUnicode(str); 2410 } 2411 2412 QString kio_krarcProtocol::decodeString(char *buf) 2413 { 2414 // Note: KRFUNC was not used here in order to avoid filling the log with too much information 2415 if (noencoding) 2416 return QTextCodec::codecForLocale()->toUnicode(buf); 2417 return codec->toUnicode(buf); 2418 } 2419 2420 QString kio_krarcProtocol::getPath(const QUrl &url, QUrl::FormattingOptions options) 2421 { 2422 // Note: KRFUNC was not used here in order to avoid filling the log with too much information 2423 QString path = url.adjusted(options).path(); 2424 REPLACE_DIR_SEP2(path); 2425 2426 #ifdef Q_OS_WIN 2427 if (path.startsWith(DIR_SEPARATOR)) { 2428 int p = 1; 2429 while (p < path.length() && path[p] == DIR_SEPARATOR_CHAR) 2430 p++; 2431 /* /C:/Folder */ 2432 if (p + 2 <= path.length() && path[p].isLetter() && path[p + 1] == ':') { 2433 path = path.mid(p); 2434 } 2435 } 2436 #endif 2437 return path; 2438 } 2439 2440 #endif // KRARC_ENABLED 2441 2442 #include "krarc.moc"