diff --git a/krArc/krarc.cpp b/krArc/krarc.cpp index 59ac6365..b7cf090e 100644 --- a/krArc/krarc.cpp +++ b/krArc/krarc.cpp @@ -1,1858 +1,1859 @@ /*************************************************************************** krarc.cpp ------------------- begin : Sat Jun 14 14:42:49 IDT 2003 copyright : (C) 2003 by Rafi Yanai & Shie Erlich email : krusader@users.sf.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krarc.h" #include "../krusader/defaults.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_IPC_SIZE (1024*32) #define TRIES_WITH_PASSWORDS 3 using namespace KIO; extern "C" { #ifdef KRARC_ENABLED /* This codec is for being able to handle files which encoding differs from the current locale. * * Unfortunately QProcess requires QString parameters for arguments which are encoded to Local8Bit * If we want to use unzip with ISO-8852-2 when the current locale is UTF-8, it will cause problems. * * Workaround: * 1. encode the QString to QByteArray ( according to the selected remote encoding, ISO-8852-2 ) * 2. encode QByteArray to QString again * unicode 0xE000-0xF7FF is for private use * the byte array is mapped to 0xE000-0xE0FF unicodes * 3. KrArcCodec maps 0xE000-0xE0FF to 0x0000-0x00FF, while calls the default encoding routine * for other unicodes. */ class KrArcCodec : public QTextCodec { public: KrArcCodec(QTextCodec * codec) : originalCodec(codec) {} virtual ~KrArcCodec() {} virtual QByteArray name() const { return originalCodec->name(); } virtual QList aliases() const { return originalCodec->aliases(); } virtual int mibEnum() const { return originalCodec->mibEnum(); } protected: virtual QString convertToUnicode(const char *in, int length, ConverterState *state) const { return originalCodec->toUnicode(in, length, state); } virtual QByteArray convertFromUnicode(const QChar *in, int length, ConverterState *state) const { // the QByteArray is embedded into the unicode charset (QProcess hell) QByteArray result; for (int i = 0; i != length; i++) { if (((in[ i ].unicode()) & 0xFF00) == 0xE000) // map 0xE000-0xE0FF to 0x0000-0x00FF result.append((char)(in[ i ].unicode() & 0xFF)); else result.append(originalCodec->fromUnicode(in + i, 1, state)); } return result; } private: QTextCodec * originalCodec; } *krArcCodec; #define SET_KRCODEC QTextCodec *origCodec = QTextCodec::codecForLocale(); \ QTextCodec::setCodecForLocale( krArcCodec ); #define RESET_KRCODEC QTextCodec::setCodecForLocale( origCodec ); #endif // KRARC_ENABLED class DummySlave : public KIO::SlaveBase { public: DummySlave(const QByteArray &pool_socket, const QByteArray &app_socket) : SlaveBase("kio_krarc", pool_socket, app_socket) { error((int)ERR_SLAVE_DEFINED, QString("krarc is disabled.")); } }; int Q_DECL_EXPORT kdemain(int argc, char **argv) { if (argc != 4) { qWarning() << "Usage: kio_krarc protocol domain-socket1 domain-socket2" << endl; exit(-1); } #ifdef KRARC_ENABLED kio_krarcProtocol slave(argv[2], argv[3]); #else DummySlave slave(argv[2], argv[3]); #endif slave.dispatchLoop(); return 0; } } // extern "C" #ifdef KRARC_ENABLED kio_krarcProtocol::kio_krarcProtocol(const QByteArray &pool_socket, const QByteArray &app_socket) : SlaveBase("kio_krarc", pool_socket, app_socket), archiveChanged(true), arcFile(0L), extArcReady(false), password(QString()), krConf("krusaderrc"), codec(0) { KRFUNC; confGrp = KConfigGroup(&krConf, "Dependencies"); KConfigGroup group(&krConf, "General"); QString tmpDirPath = group.readEntry("Temp Directory", _TempDirectory); QDir tmpDir(tmpDirPath); if(!tmpDir.exists()) { for (int i = 1 ; i != -1 ; i = tmpDirPath.indexOf('/', i + 1)) QDir().mkdir(tmpDirPath.left(i)); QDir().mkdir(tmpDirPath); } arcTempDir = tmpDirPath + DIR_SEPARATOR; QString dirName = "krArc" + QDateTime::currentDateTime().toString(Qt::ISODate); dirName.replace(QRegExp(":"), "_"); tmpDir.mkdir(dirName); arcTempDir = arcTempDir + dirName + DIR_SEPARATOR; krArcCodec = new KrArcCodec(QTextCodec::codecForLocale()); } /* ---------------------------------------------------------------------------------- */ kio_krarcProtocol::~kio_krarcProtocol() { KRFUNC; // delete the temp directory KProcess proc; proc << fullPathName("rm") << "-rf" << arcTempDir; proc.start(); proc.waitForFinished(); } /* ---------------------------------------------------------------------------------- */ bool kio_krarcProtocol::checkWriteSupport() { KRFUNC; krConf.reparseConfiguration(); if (KConfigGroup(&krConf, "kio_krarc").readEntry("EnableWrite", false)) return true; else { error(ERR_UNSUPPORTED_ACTION, i18n("krarc: write support is disabled.\n" "You can enable it on the 'Archives' page in Konfigurator.")); return false; } } void kio_krarcProtocol::receivedData(KProcess *, QByteArray &d) { KRFUNC; QByteArray buf(d); data(buf); processedSize(d.length()); decompressedLen += d.length(); } void kio_krarcProtocol::mkdir(const QUrl &url, int permissions) { KRFUNC; KRDEBUG(getPath(url)); if (!checkWriteSupport()) return; if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (newArchiveURL && !initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (putCmd.isEmpty()) { error(ERR_UNSUPPORTED_ACTION, i18n("Creating directories is not supported with %1 archives", arcType)); return; } if (arcType == "arj" || arcType == "lha") { QString arcDir = getPath(url).mid(getPath(arcFile->url()).length()); if (arcDir.right(1) != DIR_SEPARATOR) arcDir = arcDir + DIR_SEPARATOR; if (dirDict.find(arcDir) == dirDict.end()) addNewDir(arcDir); finished(); return; } QString arcDir = findArcDirectory(url); QString tempDir = arcDir.mid(1) + getPath(url).mid(getPath(url).lastIndexOf(DIR_SEPARATOR) + 1); if (tempDir.right(1) != DIR_SEPARATOR) tempDir = tempDir + DIR_SEPARATOR; if (permissions == -1) permissions = 0777; //set default permissions QByteArray arcTempDirEnc = arcTempDir.toLocal8Bit(); for (int i = 0;i < tempDir.length() && i >= 0; i = tempDir.indexOf(DIR_SEPARATOR, i + 1)) { QByteArray newDirs = encodeString(tempDir.left(i)); newDirs.prepend(arcTempDirEnc); QT_MKDIR(newDirs, permissions); } if (tempDir.endsWith(DIR_SEPARATOR)) tempDir.truncate(tempDir.length() - 1); // pack the directory KrLinecountingProcess proc; proc << putCmd << getPath(arcFile->url()) << localeEncodedString(tempDir); infoMessage(i18n("Creating %1...", url.fileName())); QDir::setCurrent(arcTempDir); SET_KRCODEC proc.start(); RESET_KRCODEC proc.waitForFinished(); // delete the temp directory QDir().rmdir(arcTempDir); if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { error(ERR_COULD_NOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); return; } // force a refresh of archive information initDirDict(url, true); finished(); } void kio_krarcProtocol::put(const QUrl &url, int permissions, KIO::JobFlags flags) { KRFUNC; KRDEBUG(getPath(url)); if (!checkWriteSupport()) return; bool overwrite = !!(flags & KIO::Overwrite); bool resume = !!(flags & KIO::Resume); if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (newArchiveURL && !initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (putCmd.isEmpty()) { error(ERR_UNSUPPORTED_ACTION, i18n("Writing to %1 archives is not supported", arcType)); return; } if (!overwrite && findFileEntry(url)) { error(ERR_FILE_ALREADY_EXIST, getPath(url)); return; } QString arcDir = findArcDirectory(url); if (arcDir.isEmpty()) KRDEBUG("arcDir is empty."); QString tempFile = arcDir.mid(1) + getPath(url).mid(getPath(url).lastIndexOf(DIR_SEPARATOR) + 1); QString tempDir = arcDir.mid(1); if (tempDir.right(1) != DIR_SEPARATOR) tempDir = tempDir + DIR_SEPARATOR; if (permissions == -1) permissions = 0777; //set default permissions QByteArray arcTempDirEnc = arcTempDir.toLocal8Bit(); for (int i = 0;i < tempDir.length() && i >= 0; i = tempDir.indexOf(DIR_SEPARATOR, i + 1)) { QByteArray newDirs = encodeString(tempDir.left(i)); newDirs.prepend(arcTempDirEnc); QT_MKDIR(newDirs, 0755); } int fd; if (resume) { QByteArray ba = encodeString(tempFile); ba.prepend(arcTempDirEnc); fd = QT_OPEN(ba, O_RDWR); // append if resuming QT_LSEEK(fd, 0, SEEK_END); // Seek to end } else { // WABA: Make sure that we keep writing permissions ourselves, // otherwise we can be in for a surprise on NFS. mode_t initialMode; if (permissions != -1) initialMode = permissions | S_IWUSR | S_IRUSR; else initialMode = 0666; QByteArray ba = encodeString(tempFile); ba.prepend(arcTempDirEnc); fd = QT_OPEN(ba, O_CREAT | O_TRUNC | O_WRONLY, initialMode); } QByteArray buffer; int readResult; do { dataReq(); readResult = readData(buffer); ::write(fd, buffer.data(), buffer.size()); } while (readResult > 0); ::close(fd); // pack the file KrLinecountingProcess proc; proc << putCmd << getPath(arcFile->url()) << localeEncodedString(tempFile); infoMessage(i18n("Packing %1...", url.fileName())); QDir::setCurrent(arcTempDir); SET_KRCODEC proc.start(); RESET_KRCODEC proc.waitForFinished(); // remove the files QDir().rmdir(arcTempDir); if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { error(ERR_COULD_NOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); return; } // force a refresh of archive information initDirDict(url, true); finished(); } void kio_krarcProtocol::get(const QUrl &url) { KRFUNC; get(url, TRIES_WITH_PASSWORDS); } void kio_krarcProtocol::get(const QUrl &url, int tries) { KRFUNC; KRDEBUG(getPath(url)); bool decompressToFile = false; if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (newArchiveURL && !initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (getCmd.isEmpty()) { error(ERR_UNSUPPORTED_ACTION, i18n("Retrieving data from %1 archives is not supported", arcType)); return; } UDSEntry* entry = findFileEntry(url); if (!entry) { error(KIO::ERR_DOES_NOT_EXIST, getPath(url)); return; } if (KFileItem(*entry, url).isDir()) { error(KIO::ERR_IS_DIRECTORY, getPath(url)); return; } KIO::filesize_t expectedSize = KFileItem(*entry, url).size(); // for RPM files extract the cpio file first if (!extArcReady && arcType == "rpm") { KrLinecountingProcess cpio; cpio << "rpm2cpio" << getPath(arcFile->url(), QUrl::StripTrailingSlash); cpio.setStandardOutputFile(arcTempDir + "contents.cpio"); cpio.start(); cpio.waitForFinished(); if (cpio.exitStatus() != QProcess::NormalExit || !checkStatus(cpio.exitCode())) { error(ERR_COULD_NOT_READ, getPath(url) + "\n\n" + cpio.getErrorMsg()); return; } extArcReady = true; } // for DEB files extract the tar file first if (!extArcReady && arcType == "deb") { KrLinecountingProcess dpkg; dpkg << cmd << "--fsys-tarfile" << getPath(arcFile->url(), QUrl::StripTrailingSlash); dpkg.setStandardOutputFile(arcTempDir + "contents.cpio"); dpkg.start(); dpkg.waitForFinished(); if (dpkg.exitStatus() != QProcess::NormalExit || !checkStatus(dpkg.exitCode())) { error(ERR_COULD_NOT_READ, getPath(url) + "\n\n" + dpkg.getErrorMsg()); return; } extArcReady = true; } // Use the external unpacker to unpack the file QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1); KrLinecountingProcess proc; if (extArcReady) { proc << getCmd << arcTempDir + "contents.cpio" << '*' + localeEncodedString(file); } else if (arcType == "arj" || arcType == "ace" || arcType == "7z") { proc << getCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash) << localeEncodedString(file); if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! proc.setStandardInputFile("/dev/ptmx"); file = url.fileName(); decompressToFile = true; } else { decompressedLen = 0; // Determine the mimetype of the file to be retrieved, and emit it. // This is mandatory in all slaves (for KRun/BrowserRun to work). QMimeDatabase db; QMimeType mt = db.mimeTypeForFile(arcTempDir + file); if (mt.isValid()) emit mimeType(mt.name()); QString escapedFilename = file; if(arcType == "zip") // left bracket needs to be escaped escapedFilename.replace("[", "[[]"); proc << getCmd << getPath(arcFile->url()); if (arcType != "gzip" && arcType != "bzip2" && arcType != "lzma" && arcType != "xz") proc << localeEncodedString(escapedFilename); connect(&proc, SIGNAL(newOutputData(KProcess *, QByteArray &)), this, SLOT(receivedData(KProcess *, QByteArray &))); proc.setMerge(false); } infoMessage(i18n("Unpacking %1...", url.fileName())); // change the working directory to our arcTempDir QDir::setCurrent(arcTempDir); SET_KRCODEC proc.setTextModeEnabled(false); proc.start(); RESET_KRCODEC proc.waitForFinished(); if (!extArcReady && !decompressToFile) { if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode()) || (arcType != "bzip2" && arcType != "lzma" && arcType != "xz" && expectedSize != decompressedLen)) { if (encrypted && tries) { invalidatePassword(); get(url, tries - 1); return; } error(KIO::ERR_ACCESS_DENIED, getPath(url) + "\n\n" + proc.getErrorMsg()); return; } } else { if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode()) || !QFileInfo(arcTempDir + file).exists()) { if (decompressToFile) QFile(arcTempDir + file).remove(); if (encrypted && tries) { invalidatePassword(); get(url, tries - 1); return; } error(KIO::ERR_ACCESS_DENIED, getPath(url)); return; } // the following block is ripped from KDE file KIO::Slave // $Id: krarc.cpp,v 1.43 2007/01/13 13:39:51 ckarai Exp $ QByteArray _path(QFile::encodeName(arcTempDir + file)); QT_STATBUF buff; if (QT_LSTAT(_path.data(), &buff) == -1) { if (errno == EACCES) error(KIO::ERR_ACCESS_DENIED, getPath(url)); else error(KIO::ERR_DOES_NOT_EXIST, getPath(url)); return; } if (S_ISDIR(buff.st_mode)) { error(KIO::ERR_IS_DIRECTORY, getPath(url)); return; } if (!S_ISREG(buff.st_mode)) { error(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url)); return; } int fd = QT_OPEN(_path.data(), O_RDONLY); if (fd < 0) { error(KIO::ERR_CANNOT_OPEN_FOR_READING, getPath(url)); return; } // Determine the mimetype of the file to be retrieved, and emit it. // This is mandatory in all slaves (for KRun/BrowserRun to work). QMimeDatabase db; QMimeType mt = db.mimeTypeForFile(arcTempDir + file); if (mt.isValid()) emit mimeType(mt.name()); KIO::filesize_t processed_size = 0; QString resumeOffset = metaData("resume"); if (!resumeOffset.isEmpty()) { bool ok; KIO::fileoffset_t offset = resumeOffset.toLongLong(&ok); if (ok && (offset > 0) && (offset < buff.st_size)) { if (QT_LSEEK(fd, offset, SEEK_SET) == offset) { canResume(); processed_size = offset; } } } totalSize(buff.st_size); char buffer[ MAX_IPC_SIZE ]; while (1) { int n = ::read(fd, buffer, MAX_IPC_SIZE); if (n == -1) { if (errno == EINTR) continue; error(KIO::ERR_COULD_NOT_READ, getPath(url)); ::close(fd); return; } if (n == 0) break; // Finished { QByteArray array = QByteArray::fromRawData(buffer, n); data(array); } processed_size += n; } data(QByteArray()); ::close(fd); processedSize(buff.st_size); finished(); if (decompressToFile) QFile(arcTempDir + file).remove(); return; } // send empty buffer to mark EOF data(QByteArray()); finished(); } void kio_krarcProtocol::del(QUrl const & url, bool isFile) { KRFUNC; KRDEBUG(getPath(url)); if (!checkWriteSupport()) return; if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (newArchiveURL && !initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (delCmd.isEmpty()) { error(ERR_UNSUPPORTED_ACTION, i18n("Deleting files from %1 archives is not supported", arcType)); return; } if (!findFileEntry(url)) { if ((arcType != "arj" && arcType != "lha") || isFile) { error(KIO::ERR_DOES_NOT_EXIST, getPath(url)); return; } } QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1); if (!isFile && file.right(1) != DIR_SEPARATOR) { if (arcType == "zip") file = file + DIR_SEPARATOR; } KrLinecountingProcess proc; proc << delCmd << getPath(arcFile->url()) << localeEncodedString(file); infoMessage(i18n("Deleting %1...", url.fileName())); SET_KRCODEC proc.start(); RESET_KRCODEC proc.waitForFinished(); if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { error(ERR_COULD_NOT_WRITE, getPath(url) + "\n\n" + proc.getErrorMsg()); return; } // force a refresh of archive information initDirDict(url, true); finished(); } void kio_krarcProtocol::stat(const QUrl &url) { KRFUNC; KRDEBUG(getPath(url)); if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (newArchiveURL && !initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (listCmd.isEmpty()) { error(ERR_UNSUPPORTED_ACTION, i18n("Accessing files is not supported with %1 archives", arcType)); return; } QString path = getPath(url, QUrl::StripTrailingSlash); QUrl newUrl = url; // but treat the archive itself as the archive root if (path == getPath(arcFile->url(), QUrl::StripTrailingSlash)) { newUrl.setPath(path + DIR_SEPARATOR); path = getPath(newUrl); } // we might be stating a real file if (QFileInfo(path).exists()) { QT_STATBUF buff; QT_STAT(path.toLocal8Bit(), &buff); QString mime; QMimeDatabase db; QMimeType result = db.mimeTypeForFile(path); if (result.isValid()) mime = result.name(); statEntry(KFileItem(QUrl::fromLocalFile(path), mime, buff.st_mode).entry()); finished(); return; } UDSEntry* entry = findFileEntry(newUrl); if (entry) { statEntry(*entry); finished(); } else error(KIO::ERR_DOES_NOT_EXIST, path); } void kio_krarcProtocol::copy(const QUrl &url, const QUrl &dest, int, KIO::JobFlags flags) { KRDEBUG("source: " << url.path() << " dest: " << dest.path()); if (!checkWriteSupport()) return; bool overwrite = !!(flags & KIO::Overwrite); // KDE HACK: opening the password dlg in copy causes error for the COPY, and further problems // that's why encrypted files are not allowed to copy if (!encrypted && dest.isLocalFile()) do { if (url.fileName() != dest.fileName()) break; if (QTextCodec::codecForLocale()->name() != codec->name()) break; //the file exists and we don't want to overwrite if ((!overwrite) && (QFile(getPath(dest)).exists())) { error((int)ERR_FILE_ALREADY_EXIST, QString(QFile::encodeName(getPath(dest)))); return; }; if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (newArchiveURL && !initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } UDSEntry* entry = findFileEntry(url); if (copyCmd.isEmpty() || !entry) break; QString file = getPath(url).mid(getPath(arcFile->url()).length() + 1); QString destDir = getPath(dest, QUrl::StripTrailingSlash); if (!QDir(destDir).exists()) { int ndx = destDir.lastIndexOf(DIR_SEPARATOR_CHAR); if (ndx != -1) destDir.truncate(ndx + 1); } QDir::setCurrent(destDir); QString escapedFilename = file; - if(arcType == "zip") // left bracket needs to be escaped + if(arcType == "zip") { + // left bracket needs to be escaped escapedFilename.replace("[", "[[]"); + } KrLinecountingProcess proc; proc << copyCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash) << escapedFilename; if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! proc.setStandardInputFile("/dev/ptmx"); proc.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect infoMessage(i18n("Unpacking %1...", url.fileName())); proc.start(); proc.waitForFinished(); if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) { error(KIO::ERR_COULD_NOT_WRITE, getPath(dest, QUrl::StripTrailingSlash) + "\n\n" + proc.getErrorMsg()); return; } if (!QFileInfo(getPath(dest, QUrl::StripTrailingSlash)).exists()) { error(KIO::ERR_COULD_NOT_WRITE, getPath(dest, QUrl::StripTrailingSlash)); return; } processedSize(KFileItem(*entry, url).size()); finished(); QDir::setCurrent(QDir::rootPath()); /* for being able to umount devices after copying*/ return; } while (0); if (encrypted) KRDEBUG("ERROR: " << url.path() << " is encrypted."); if (!dest.isLocalFile()) KRDEBUG("ERROR: " << url.path() << " is not a local file."); // CMD_COPY is no more in KF5 - replaced with 74 value (as stated in kio/src/core/commands_p.h, which could be found in quickgit.kde.org/?p=kio.git&a=tree) error(ERR_UNSUPPORTED_ACTION, unsupportedActionErrorString(mProtocol, 74)); } void kio_krarcProtocol::listDir(const QUrl &url) { KRFUNC; KRDEBUG(getPath(url)); if (!setArcFile(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } if (listCmd.isEmpty()) { error(ERR_UNSUPPORTED_ACTION, i18n("Listing directories is not supported for %1 archives", arcType)); return; } QString path = getPath(url); if (path.right(1) != DIR_SEPARATOR) path = path + DIR_SEPARATOR; // it might be a real dir ! if (QFileInfo(path).exists()) { if (QFileInfo(path).isDir()) { QUrl redir; redir.setPath(getPath(url)); redirection(redir); finished(); } else { // maybe it's an archive ! error(ERR_IS_FILE, path); } return; } if (!initDirDict(url)) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } QString arcDir = path.mid(getPath(arcFile->url()).length()); arcDir.truncate(arcDir.lastIndexOf(DIR_SEPARATOR)); if (arcDir.right(1) != DIR_SEPARATOR) arcDir = arcDir + DIR_SEPARATOR; if (dirDict.find(arcDir) == dirDict.end()) { error(ERR_CANNOT_ENTER_DIRECTORY, getPath(url)); return; } UDSEntryList* dirList = dirDict[ arcDir ]; totalSize(dirList->size()); listEntries(*dirList); finished(); } bool kio_krarcProtocol::setArcFile(const QUrl &url) { KRFUNC; KRDEBUG(url.fileName()); QString path = getPath(url); time_t currTime = time(0); archiveChanged = true; newArchiveURL = true; // is the file already set ? if (arcFile && getPath(arcFile->url(), QUrl::StripTrailingSlash) == path.left(getPath(arcFile->url(), QUrl::StripTrailingSlash).length())) { newArchiveURL = false; // Has it changed ? KFileItem* newArcFile = new KFileItem(arcFile->url(), QString(), arcFile->mode()); if (metaData("Charset") != currentCharset || !newArcFile->cmp(*arcFile)) { currentCharset = metaData("Charset"); codec = QTextCodec::codecForName(currentCharset.toLatin1()); if (codec == 0) codec = QTextCodec::codecForMib(4 /* latin-1 */); delete arcFile; password.clear(); extArcReady = false; arcFile = newArcFile; } else { // same old file delete newArcFile; archiveChanged = false; if (encrypted && password.isNull()) initArcParameters(); } } else { // it's a new file... extArcReady = false; if (arcFile) { delete arcFile; password.clear(); arcFile = 0L; } QString newPath = path; if (newPath.right(1) != DIR_SEPARATOR) newPath = newPath + DIR_SEPARATOR; for (int pos = 0; pos >= 0; pos = newPath.indexOf(DIR_SEPARATOR, pos + 1)) { QFileInfo qfi(newPath.left(pos)); if (qfi.exists() && !qfi.isDir()) { QT_STATBUF stat_p; QT_LSTAT(newPath.left(pos).toLocal8Bit(), &stat_p); arcFile = new KFileItem(QUrl::fromLocalFile(newPath.left(pos)), QString(), stat_p.st_mode); break; } } if (!arcFile) { // KRDEBUG("ERROR: " << path << " does not exist."); error(ERR_DOES_NOT_EXIST, path); return false; // file not found } currentCharset = metaData("Charset"); codec = QTextCodec::codecForName(currentCharset.toLatin1()); if (codec == 0) codec = QTextCodec::codecForMib(4 /* latin-1 */); } /* FIX: file change can only be detected if the timestamp between the two consequent changes is more than 1s. If the archive is continuously changing (check: move files inside the archive), krarc may erronously think, that the archive file is unchanged, because the timestamp is the same as the previous one. This situation can only occur if the modification time equals with the current time. While this condition is true, we can say, that the archive is changing, so content reread is always necessary during that period. */ if (archiveChanging) archiveChanged = true; archiveChanging = (currTime == (time_t)arcFile->time(KFileItem::ModificationTime).toTime_t()); arcPath = getPath(arcFile->url(), QUrl::StripTrailingSlash); arcType = detectArchive(encrypted, arcPath); if (arcType == "tbz") arcType = "bzip2"; else if (arcType == "tgz") arcType = "gzip"; else if (arcType == "tlz") arcType = "lzma"; else if (arcType == "txz") arcType = "xz"; if (arcType.isEmpty()) { arcType = arcFile->mimetype(); - arcType = arcType.mid(arcType.lastIndexOf("-") + 1); - + arcType = getShortTypeFromMime(arcType); if (arcType == "jar") arcType = "zip"; } return initArcParameters(); } bool kio_krarcProtocol::initDirDict(const QUrl &url, bool forced) { KRFUNC; KRDEBUG(getPath(url)); // set the archive location //if( !setArcFile(getPath(url)) ) return false; // no need to rescan the archive if it's not changed // KRDEBUG("achiveChanged: " << archiveChanged << " forced: " << forced); if (!archiveChanged && !forced) { // KRDEBUG("doing nothing."); return true; } extArcReady = false; if (!setArcFile(url)) return false; /* if the archive was changed refresh the file information */ // write the temp file KrLinecountingProcess proc; QTemporaryFile temp; // parse the temp file if (!temp.open()) { error(ERR_COULD_NOT_READ, temp.fileName()); return false; } if (arcType != "bzip2" && arcType != "lzma" && arcType != "xz") { if (arcType == "rpm") { proc << listCmd << arcPath; proc.setStandardOutputFile(temp.fileName()); } else { proc << listCmd << getPath(arcFile->url(), QUrl::StripTrailingSlash); proc.setStandardOutputFile(temp.fileName()); } if (arcType == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! proc.setStandardInputFile("/dev/ptmx"); proc.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect proc.start(); proc.waitForFinished(); if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(proc.exitCode())) return false; } // clear the dir dictionary QHashIterator< QString, KIO::UDSEntryList *> lit(dirDict); while (lit.hasNext()) delete lit.next().value(); dirDict.clear(); // add the "/" directory UDSEntryList* root = new UDSEntryList(); dirDict.insert(DIR_SEPARATOR, root); // and the "/" UDSEntry UDSEntry entry; entry.insert(KIO::UDSEntry::UDS_NAME, "."); mode_t mode = parsePermString("drwxr-xr-x"); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only entry.insert(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only root->append(entry); if (arcType == "bzip2" || arcType == "lzma" || arcType == "xz") abort(); char buf[1000]; QString line; int lineNo = 0; bool invalidLine = false; // the rar list is started with a ------ line. if (arcType == "rar" || arcType == "arj" || arcType == "lha" || arcType == "7z") { while (temp.readLine(buf, 1000) != -1) { line = decodeString(buf); if (line.startsWith(QLatin1String("----------"))) break; } } while (temp.readLine(buf, 1000) != -1) { line = decodeString(buf); if (arcType == "rar") { // the rar list is ended with a ------ line. if (line.startsWith(QLatin1String("----------"))) { invalidLine = !invalidLine; break; } if (invalidLine) continue; else { if (line[0] == '*') // encrypted archives starts with '*' line[0] = ' '; } } if (arcType == "ace") { // the ace list begins with a number. if (!line[0].isDigit()) continue; } if (arcType == "arj") { // the arj list is ended with a ------ line. if (line.startsWith(QLatin1String("----------"))) { invalidLine = !invalidLine; continue; } if (invalidLine) continue; else { temp.readLine(buf, 1000); line = line + decodeString(buf); temp.readLine(buf, 1000); line = line + decodeString(buf); temp.readLine(buf, 1000); line = line + decodeString(buf); } } if (arcType == "lha" || arcType == "7z") { // the arj list is ended with a ------ line. if (line.startsWith(QLatin1String("----------"))) break; } parseLine(lineNo++, line.trimmed()); } // close and delete our file temp.close(); archiveChanged = false; // KRDEBUG("done."); return true; } QString kio_krarcProtocol::findArcDirectory(const QUrl &url) { KRFUNC; KRDEBUG(url.fileName()); QString path = getPath(url); if (path.right(1) == DIR_SEPARATOR) path.truncate(path.length() - 1); if (!initDirDict(url)) { return QString(); } QString arcDir = path.mid(getPath(arcFile->url()).length()); arcDir.truncate(arcDir.lastIndexOf(DIR_SEPARATOR)); if (arcDir.right(1) != DIR_SEPARATOR) arcDir = arcDir + DIR_SEPARATOR; return arcDir; } UDSEntry* kio_krarcProtocol::findFileEntry(const QUrl &url) { KRFUNC; QString arcDir = findArcDirectory(url); if (arcDir.isEmpty()) return 0; QHash::iterator itef = dirDict.find(arcDir); if (itef == dirDict.end()) return 0; UDSEntryList* dirList = itef.value(); QString name = getPath(url); if (getPath(arcFile->url(), QUrl::StripTrailingSlash) == getPath(url, QUrl::StripTrailingSlash)) name = '.'; // the '/' case else { if (name.right(1) == DIR_SEPARATOR) name.truncate(name.length() - 1); name = name.mid(name.lastIndexOf(DIR_SEPARATOR) + 1); } UDSEntryList::iterator entry; for (entry = dirList->begin(); entry != dirList->end(); ++entry) { if ((entry->contains(KIO::UDSEntry::UDS_NAME)) && (entry->stringValue(KIO::UDSEntry::UDS_NAME) == name)) return &(*entry); } return 0; } QString kio_krarcProtocol::nextWord(QString &s, char d) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information s = s.trimmed(); int j = s.indexOf(d, 0); QString temp = s.left(j); // find the leftmost word. s.remove(0, j); return temp; } mode_t kio_krarcProtocol::parsePermString(QString perm) { KRFUNC; mode_t mode = 0; // file type if (perm[0] == 'd') mode |= S_IFDIR; #ifndef Q_WS_WIN if (perm[0] == 'l') mode |= S_IFLNK; #endif if (perm[0] == '-') mode |= S_IFREG; // owner permissions if (perm[1] != '-') mode |= S_IRUSR; if (perm[2] != '-') mode |= S_IWUSR; if (perm[3] != '-') mode |= S_IXUSR; #ifndef Q_WS_WIN // group permissions if (perm[4] != '-') mode |= S_IRGRP; if (perm[5] != '-') mode |= S_IWGRP; if (perm[6] != '-') mode |= S_IXGRP; // other permissions if (perm[7] != '-') mode |= S_IROTH; if (perm[8] != '-') mode |= S_IWOTH; if (perm[9] != '-') mode |= S_IXOTH; #endif return mode; } UDSEntryList* kio_krarcProtocol::addNewDir(QString path) { KRFUNC; UDSEntryList* dir; // check if the current dir exists QHash::iterator itef = dirDict.find(path); if (itef != dirDict.end()) return itef.value(); // set dir to the parent dir dir = addNewDir(path.left(path.lastIndexOf(DIR_SEPARATOR, -2) + 1)); // add a new entry in the parent dir QString name = path.mid(path.lastIndexOf(DIR_SEPARATOR, -2) + 1); name = name.left(name.length() - 1); if (name == "." || name == "..") { // entries with these names wouldn't be displayed // don't translate since this is an internal error QString err = QString("Cannot handle path: ") + path; // KRDEBUG("ERROR: " << err); error(KIO::ERR_INTERNAL, err); exit(); } UDSEntry entry; entry.insert(KIO::UDSEntry::UDS_NAME, name); mode_t mode = parsePermString("drwxr-xr-x"); entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only entry.insert(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only entry.insert(KIO::UDSEntry::UDS_SIZE, 0); entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, arcFile->time(KFileItem::ModificationTime).toTime_t()); dir->append(entry); // create a new directory entry and add it.. dir = new UDSEntryList(); dirDict.insert(path, dir); return dir; } void kio_krarcProtocol::parseLine(int lineNo, QString line) { KRFUNC; UDSEntryList* dir; UDSEntry entry; QString owner; QString group; QString symlinkDest; QString perm; mode_t mode = 0666; size_t size = 0; time_t time = ::time(0); QString fullName; if (arcType == "zip") { // permissions perm = nextWord(line); // ignore the next 2 fields nextWord(line); nextWord(line); // size size = nextWord(line).toLong(); // ignore the next 2 fields nextWord(line);nextWord(line); // date & time QString d = nextWord(line); QDate qdate(d.mid(0, 4).toInt(), d.mid(4, 2).toInt(), d.mid(6, 2).toInt()); QTime qtime(d.mid(9, 2).toInt(), d.mid(11, 2).toInt(), d.mid(13, 2).toInt()); time = QDateTime(qdate, qtime).toTime_t(); // full name fullName = nextWord(line, '\n'); if (perm.length() != 10) perm = (perm.at(0) == 'd' || fullName.endsWith(DIR_SEPARATOR)) ? "drwxr-xr-x" : "-rw-r--r--" ; mode = parsePermString(perm); } if (arcType == "rar") { // permissions perm = nextWord(line); // size size = nextWord(line).toLong(); // ignore the next 2 fields : packed size and compression ration nextWord(line); nextWord(line); // date & time QString d = nextWord(line); int year = 1900 + d.mid(6, 2).toInt(); if (year < 1930) year += 100; QDate qdate(year, d.mid(3, 2).toInt(), d.mid(0, 2).toInt()); QString t = nextWord(line); QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); time = QDateTime(qdate, qtime).toTime_t(); // checksum : ignored nextWord(line); // full name fullName = nextWord(line, '\n'); if (perm.length() == 7) { // windows rar permission format bool isDir = (perm.at(1).toLower() == 'd'); bool isReadOnly = (perm.at(2).toLower() == 'r'); perm = isDir ? "drwxr-xr-x" : "-rw-r--r--"; if (isReadOnly) perm[ 2 ] = '-'; } if (perm.length() != 10) perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--" ; mode = parsePermString(perm); } if (arcType == "arj") { nextWord(line); // full name fullName = nextWord(line, '\n'); // ignore the next 2 fields nextWord(line); nextWord(line); // size size = nextWord(line).toLong(); // ignore the next 2 fields nextWord(line); nextWord(line); // date & time QString d = nextWord(line); int year = 1900 + d.mid(0, 2).toInt(); if (year < 1930) year += 100; QDate qdate(year, d.mid(3, 2).toInt(), d.mid(6, 2).toInt()); QString t = nextWord(line); QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); time = QDateTime(qdate, qtime).toTime_t(); // permissions perm = nextWord(line); if (perm.length() != 10) perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--" ; mode = parsePermString(perm); } if (arcType == "rpm") { // full name fullName = nextWord(line); // size size = nextWord(line).toULong(); // date & time time = nextWord(line).toULong(); // next field is md5sum, ignore it nextWord(line); // permissions mode = nextWord(line).toULong(0, 8); // Owner & Group owner = nextWord(line); group = nextWord(line); // symlink destination #ifndef Q_WS_WIN if (S_ISLNK(mode)) { // ignore the next 3 fields nextWord(line); nextWord(line); nextWord(line); symlinkDest = nextWord(line); } #endif } if (arcType == "gzip") { if (!lineNo) return; //ignore the first line // first field is uncompressed size - ignore it nextWord(line); // size size = nextWord(line).toULong(); // ignore the next field nextWord(line); // full name fullName = nextWord(line); fullName = fullName.mid(fullName.lastIndexOf(DIR_SEPARATOR) + 1); } if (arcType == "lzma") { fullName = arcFile->name(); if (fullName.endsWith(QLatin1String("lzma"))) { fullName.truncate(fullName.length() - 5); } mode = arcFile->mode(); size = arcFile->size(); } if (arcType == "xz") { fullName = arcFile->name(); if (fullName.endsWith(QLatin1String("xz"))) { fullName.truncate(fullName.length() - 3); } mode = arcFile->mode(); size = arcFile->size(); } if (arcType == "bzip2") { // There is no way to list bzip2 files, so we take our information from // the archive itself... fullName = arcFile->name(); if (fullName.endsWith(QLatin1String("bz2"))) { fullName.truncate(fullName.length() - 4); } mode = arcFile->mode(); size = arcFile->size(); } if (arcType == "lha") { // permissions perm = nextWord(line); if (perm.length() != 10) perm = (perm.at(0) == 'd') ? "drwxr-xr-x" : "-rw-r--r--" ; mode = parsePermString(perm); // ignore the next field nextWord(line); // size size = nextWord(line).toLong(); // ignore the next field nextWord(line); // date & time int month = (QString("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec").split(',')).indexOf(nextWord(line)) + 1; int day = nextWord(line).toInt(); int year = QDate::currentDate().year(); QString third = nextWord(line); QTime qtime; if (third.contains(":")) qtime = QTime::fromString(third); else year = third.toInt(); QDate qdate(year, month, day); time = QDateTime(qdate, qtime).toTime_t(); // full name fullName = nextWord(line, '\n'); } if (arcType == "ace") { // date & time QString d = nextWord(line); int year = 1900 + d.mid(6, 2).toInt(); if (year < 1930) year += 100; QDate qdate(year, d.mid(3, 2).toInt(), d.mid(0, 2).toInt()); QString t = nextWord(line); QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); time = QDateTime(qdate, qtime).toTime_t(); // ignore the next field nextWord(line); // size size = nextWord(line).toLong(); // ignore the next field nextWord(line); // full name fullName = nextWord(line, '\n'); if (fullName[ 0 ] == '*') // encrypted archives starts with '*' fullName = fullName.mid(1); } if (arcType == "deb") { // permissions perm = nextWord(line); mode = parsePermString(perm); // Owner & Group owner = nextWord(line, DIR_SEPARATOR_CHAR); group = nextWord(line).mid(1); // size size = nextWord(line).toLong(); // date & time QString d = nextWord(line); QDate qdate(d.mid(0, 4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt()); QString t = nextWord(line); QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), 0); time = QDateTime(qdate, qtime).toTime_t(); // full name fullName = nextWord(line, '\n').mid(1); //if ( fullName.right( 1 ) == "/" ) return; if (fullName.contains("->")) { symlinkDest = fullName.mid(fullName.indexOf("->") + 2); fullName = fullName.left(fullName.indexOf("->") - 1); } } if (arcType == "7z") { // date & time QString d = nextWord(line); QDate qdate(d.mid(0, 4).toInt(), d.mid(5, 2).toInt(), d.mid(8, 2).toInt()); QString t = nextWord(line); QTime qtime(t.mid(0, 2).toInt(), t.mid(3, 2).toInt(), t.mid(6, 2).toInt()); time = QDateTime(qdate, qtime).toTime_t(); // permissions perm = nextWord(line); bool isDir = (perm.at(0).toLower() == 'd'); bool isReadOnly = (perm.at(1).toLower() == 'r'); perm = isDir ? "drwxr-xr-x" : "-rw-r--r--"; if (isReadOnly) perm[ 2 ] = '-'; mode = parsePermString(perm); // size size = nextWord(line).toLong(); // ignore the next 15 characters line = line.mid(15); // full name fullName = nextWord(line, '\n'); } if (fullName.right(1) == DIR_SEPARATOR) fullName = fullName.left(fullName.length() - 1); if (!fullName.startsWith(DIR_SEPARATOR)) fullName = DIR_SEPARATOR + fullName; QString path = fullName.left(fullName.lastIndexOf(DIR_SEPARATOR) + 1); // set/create the directory UDSEntryList QHash::iterator itef = dirDict.find(path); if (itef == dirDict.end()) dir = addNewDir(path); else dir = itef.value(); QString name = fullName.mid(fullName.lastIndexOf(DIR_SEPARATOR) + 1); // file name entry.insert(KIO::UDSEntry::UDS_NAME, name); // file type entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, mode & S_IFMT); // keep file type only // file permissions entry.insert(KIO::UDSEntry::UDS_ACCESS, mode & 07777); // keep permissions only // file size entry.insert(KIO::UDSEntry::UDS_SIZE, size); // modification time entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, time); // link destination if (!symlinkDest.isEmpty()) { entry.insert(KIO::UDSEntry::UDS_LINK_DEST, symlinkDest); } if (S_ISDIR(mode)) { fullName = fullName + DIR_SEPARATOR; if (dirDict.find(fullName) == dirDict.end()) dirDict.insert(fullName, new UDSEntryList()); else { // try to overwrite an existing entry UDSEntryList::iterator entryIt; for (entryIt = dir->begin(); entryIt != dir->end(); ++entryIt) { if (entryIt->contains(KIO::UDSEntry::UDS_NAME) && entryIt->stringValue(KIO::UDSEntry::UDS_NAME) == name) { entryIt->insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, time); entryIt->insert(KIO::UDSEntry::UDS_ACCESS, mode); return; } } return; // there is already an entry for this directory } } // multi volume archives can add a file twice, use only one UDSEntryList::iterator dirEntryIt; for (dirEntryIt = dir->begin(); dirEntryIt != dir->end(); ++dirEntryIt) if (dirEntryIt->contains(KIO::UDSEntry::UDS_NAME) && dirEntryIt->stringValue(KIO::UDSEntry::UDS_NAME) == name) return; dir->append(entry); } bool kio_krarcProtocol::initArcParameters() { KRFUNC; KRDEBUG("arcType: " << arcType); noencoding = false; cmd.clear(); listCmd = QStringList(); getCmd = QStringList(); copyCmd = QStringList(); delCmd = QStringList(); putCmd = QStringList(); if (arcType == "zip") { noencoding = true; cmd = fullPathName("unzip"); listCmd << fullPathName("unzip") << "-ZTs-z-t-h"; getCmd << fullPathName("unzip") << "-p"; copyCmd << fullPathName("unzip") << "-jo"; if (QStandardPaths::findExecutable(QStringLiteral("zip")).isEmpty()) { delCmd = QStringList(); putCmd = QStringList(); } else { delCmd << fullPathName("zip") << "-d"; putCmd << fullPathName("zip") << "-ry"; } if (!getPassword().isEmpty()) { getCmd << "-P" << password; copyCmd << "-P" << password; putCmd << "-P" << password; } } else if (arcType == "rar") { noencoding = true; if (QStandardPaths::findExecutable(QStringLiteral("rar")).isEmpty()) { cmd = fullPathName("unrar"); listCmd << fullPathName("unrar") << "-c-" << "-v" << "v"; getCmd << fullPathName("unrar") << "p" << "-ierr" << "-idp" << "-c-" << "-y"; copyCmd << fullPathName("unrar") << "e" << "-y"; delCmd = QStringList(); putCmd = QStringList(); } else { cmd = fullPathName("rar"); listCmd << fullPathName("rar") << "-c-" << "-v" << "v"; getCmd << fullPathName("rar") << "p" << "-ierr" << "-idp" << "-c-" << "-y"; copyCmd << fullPathName("rar") << "e" << "-y"; delCmd << fullPathName("rar") << "d"; putCmd << fullPathName("rar") << "-r" << "a"; } if (!getPassword().isEmpty()) { getCmd << QString("-p%1").arg(password); listCmd << QString("-p%1").arg(password); copyCmd << QString("-p%1").arg(password); if (!putCmd.isEmpty()) { putCmd << QString("-p%1").arg(password); delCmd << QString("-p%1").arg(password); } } } else if (arcType == "rpm") { cmd = fullPathName("rpm"); listCmd << fullPathName("rpm") << "--dump" << "-lpq"; getCmd << fullPathName("cpio") << "--force-local" << "--no-absolute-filenames" << "-iuvdF"; delCmd = QStringList(); putCmd = QStringList(); copyCmd = QStringList(); } else if (arcType == "gzip") { cmd = fullPathName("gzip"); listCmd << fullPathName("gzip") << "-l"; getCmd << fullPathName("gzip") << "-dc"; copyCmd = QStringList(); delCmd = QStringList(); putCmd = QStringList(); } else if (arcType == "bzip2") { cmd = fullPathName("bzip2"); listCmd << fullPathName("bzip2"); getCmd << fullPathName("bzip2") << "-dc"; copyCmd = QStringList(); delCmd = QStringList(); putCmd = QStringList(); } else if (arcType == "lzma") { cmd = fullPathName("lzma"); listCmd << fullPathName("lzma"); getCmd << fullPathName("lzma") << "-dc"; copyCmd = QStringList(); delCmd = QStringList(); putCmd = QStringList(); } else if (arcType == "xz") { cmd = fullPathName("xz"); listCmd << fullPathName("xz"); getCmd << fullPathName("xz") << "-dc"; copyCmd = QStringList(); delCmd = QStringList(); putCmd = QStringList(); } else if (arcType == "arj") { cmd = fullPathName("arj"); listCmd << fullPathName("arj") << "v" << "-y" << "-v"; getCmd << fullPathName("arj") << "-jyov" << "-v" << "e"; copyCmd << fullPathName("arj") << "-jyov" << "-v" << "e"; delCmd << fullPathName("arj") << "d"; putCmd << fullPathName("arj") << "-r" << "a"; if (!getPassword().isEmpty()) { getCmd << QString("-g%1").arg(password); copyCmd << QString("-g%1").arg(password); putCmd << QString("-g%1").arg(password); } } else if (arcType == "lha") { cmd = fullPathName("lha"); listCmd << fullPathName("lha") << "l"; getCmd << fullPathName("lha") << "pq"; copyCmd << fullPathName("lha") << "eif"; delCmd << fullPathName("lha") << "d"; putCmd << fullPathName("lha") << "a"; } else if (arcType == "ace") { cmd = fullPathName("unace"); listCmd << fullPathName("unace") << "v"; getCmd << fullPathName("unace") << "e" << "-o"; copyCmd << fullPathName("unace") << "e" << "-o"; delCmd = QStringList(); putCmd = QStringList(); if (!getPassword().isEmpty()) { getCmd << QString("-p%1").arg(password); copyCmd << QString("-p%1").arg(password); } } else if (arcType == "deb") { cmd = fullPathName("dpkg"); listCmd << fullPathName("dpkg") << "-c"; getCmd << fullPathName("tar") << "xvf"; copyCmd = QStringList(); delCmd = QStringList(); putCmd = QStringList(); } else if (arcType == "7z") { noencoding = true; cmd = fullPathName("7z"); if (QStandardPaths::findExecutable(cmd).isEmpty()) cmd = fullPathName("7za"); listCmd << cmd << "l" << "-y"; getCmd << cmd << "e" << "-y"; copyCmd << cmd << "e" << "-y"; delCmd << cmd << "d" << "-y"; putCmd << cmd << "a" << "-y"; if (!getPassword().isEmpty()) { getCmd << QString("-p%1").arg(password); listCmd << QString("-p%1").arg(password); copyCmd << QString("-p%1").arg(password); if (!putCmd.isEmpty()) { putCmd << QString("-p%1").arg(password); delCmd << QString("-p%1").arg(password); } } } // checking if it's an absolute path #ifdef Q_WS_WIN if (cmd.length() > 2 && cmd[ 0 ].isLetter() && cmd[ 1 ] == ':') return true; #else if (cmd.startsWith(DIR_SEPARATOR)) return true; #endif if (QStandardPaths::findExecutable(cmd).isEmpty()) { error(KIO::ERR_CANNOT_LAUNCH_PROCESS, cmd + i18n("\nMake sure that the %1 binary is installed properly on your system.", cmd)); KRDEBUG("Failed to find cmd: " << cmd); return false; } return true; } bool kio_krarcProtocol::checkStatus(int exitCode) { KRFUNC; KRDEBUG(exitCode); // if this code is changed, the code of KRarcHandler::checkStatus() must be reviewed if (arcType == "zip" || arcType == "rar" || arcType == "7z") return exitCode == 0 || exitCode == 1; else if (arcType == "ace" || arcType == "bzip2" || arcType == "lha" || arcType == "rpm" || arcType == "arj") return exitCode == 0; else if (arcType == "gzip" || arcType == "lzma" || arcType == "xz") return exitCode == 0 || exitCode == 2; else return exitCode == 0; } void kio_krarcProtocol::checkIf7zIsEncrypted(bool &encrypted, QString fileName) { KRFUNC; if (encryptedArchPath == fileName) encrypted = true; else { // we try to find whether the 7z archive is encrypted // this is hard as the headers are also compressed QString tester = fullPathName("7z"); if (QStandardPaths::findExecutable(tester).isEmpty()) { KRDEBUG("A 7z program was not found"); tester = fullPathName("7za"); if (QStandardPaths::findExecutable(tester).isEmpty()) { KRDEBUG("A 7za program was not found"); return; } } QString testCmd = tester + " t -y "; lastData = encryptedArchPath = ""; KrLinecountingProcess proc; proc << testCmd << fileName; connect(&proc, SIGNAL(newOutputData(KProcess *, QByteArray &)), this, SLOT(checkOutputForPassword(KProcess *, QByteArray &))); proc.start(); proc.waitForFinished(); encrypted = this->encrypted; if (encrypted) encryptedArchPath = fileName; } } void kio_krarcProtocol::checkOutputForPassword(KProcess * proc, QByteArray & buf) { KRFUNC; QString data = QString(buf); QString checkable = lastData + data; QStringList lines = checkable.split('\n'); lastData = lines[ lines.count() - 1 ]; for (int i = 0; i != lines.count(); i++) { QString line = lines[ i ].trimmed().toLower(); int ndx = line.indexOf("testing"); if (ndx >= 0) line.truncate(ndx); if (line.isEmpty()) continue; if (line.contains("password") && line.contains("enter")) { KRDEBUG("Encrypted 7z archive found!"); encrypted = true; proc->kill(); return; } } } void kio_krarcProtocol::invalidatePassword() { KRFUNC; KRDEBUG(getPath(arcFile->url(), QUrl::StripTrailingSlash) + DIR_SEPARATOR); if (!encrypted) return; KIO::AuthInfo authInfo; authInfo.caption = i18n("Krarc Password Dialog"); authInfo.username = "archive"; authInfo.readOnly = true; authInfo.keepPassword = true; authInfo.verifyPath = true; QString fileName = getPath(arcFile->url(), QUrl::StripTrailingSlash); authInfo.url = QUrl::fromLocalFile(ROOT_DIR); authInfo.url.setHost(fileName /*.replace('/','_')*/); authInfo.url.setScheme("krarc"); password.clear(); cacheAuthentication(authInfo); } QString kio_krarcProtocol::getPassword() { KRFUNC; KRDEBUG("Encrypted: " << encrypted); if (!password.isNull()) return password; if (!encrypted) return (password = ""); KIO::AuthInfo authInfo; authInfo.caption = i18n("Krarc Password Dialog"); authInfo.username = "archive"; authInfo.readOnly = true; authInfo.keepPassword = true; authInfo.verifyPath = true; QString fileName = getPath(arcFile->url(), QUrl::StripTrailingSlash); authInfo.url = QUrl::fromLocalFile(ROOT_DIR); authInfo.url.setHost(fileName /*.replace('/','_')*/); authInfo.url.setScheme("krarc"); if (checkCachedAuthentication(authInfo) && !authInfo.password.isNull()) { KRDEBUG(authInfo.password); return (password = authInfo.password); } authInfo.password.clear(); if (openPasswordDialog(authInfo, i18n("Accessing the file requires a password.")) && !authInfo.password.isNull()) { KRDEBUG(authInfo.password); return (password = authInfo.password); } KRDEBUG(password); return password; } QString kio_krarcProtocol::detectFullPathName(QString name) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information KRDEBUG(name); name = name + EXEC_SUFFIX; QStringList path = QString::fromLocal8Bit(qgetenv("PATH")).split(':'); for (QStringList::Iterator it = path.begin(); it != path.end(); ++it) { if (QDir(*it).exists(name)) { QString dir = *it; if (!dir.endsWith(DIR_SEPARATOR)) dir += DIR_SEPARATOR; return dir + name; } } return name; } QString kio_krarcProtocol::fullPathName(QString name) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information KRDEBUG(name); QString supposedName = confGrp.readEntry(name, QString()); if (supposedName.isEmpty()) supposedName = detectFullPathName(name); return supposedName; } QString kio_krarcProtocol::localeEncodedString(QString str) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information if (noencoding) return str; QByteArray array = codec->fromUnicode(str); // encoding the byte array to QString, mapping 0x0000-0x00FF to 0xE000-0xE0FF // see KrArcCodec for more explanation int size = array.size(); QString result; const char *data = array.data(); for (int i = 0; i != size; i++) { unsigned short ch = (((int)data[ i ]) & 0xFF) + 0xE000; // user defined character result.append(QChar(ch)); } return result; } QByteArray kio_krarcProtocol::encodeString(QString str) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information if (noencoding) return QTextCodec::codecForLocale()->fromUnicode(str); return codec->fromUnicode(str); } QString kio_krarcProtocol::decodeString(char * buf) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information if (noencoding) return QTextCodec::codecForLocale()->toUnicode(buf); return codec->toUnicode(buf); } QString kio_krarcProtocol::getPath(const QUrl &url, QUrl::FormattingOptions options) { // Note: KRFUNC was not used here in order to avoid filling the log with too much information QString path = url.adjusted(options).path(); REPLACE_DIR_SEP2(path); #ifdef Q_WS_WIN if (path.startsWith(DIR_SEPARATOR)) { int p = 1; while (p < path.length() && path[ p ] == DIR_SEPARATOR_CHAR) p++; /* /C:/Folder */ if (p + 2 <= path.length() && path[ p ].isLetter() && path[ p + 1 ] == ':') { path = path.mid(p); } } #endif return path; } #endif // KRARC_ENABLED diff --git a/krArc/krarcbasemanager.cpp b/krArc/krarcbasemanager.cpp index 00669d57..73f275fd 100644 --- a/krArc/krarcbasemanager.cpp +++ b/krArc/krarcbasemanager.cpp @@ -1,175 +1,210 @@ /*************************************************************************** krarcbasemanager.cpp -------------------- copyright : (C) 2003 by Rafi Yanai & Shie Erlich email : krusader@users.sf.net web site : http://krusader.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krarcbasemanager.h" #include KrArcBaseManager::AutoDetectParams KrArcBaseManager::autoDetectParams[] = {{"zip", 0, "PK\x03\x04"}, {"rar", 0, "Rar!\x1a" }, {"arj", 0, "\x60\xea" }, {"rpm", 0, "\xed\xab\xee\xdb"}, {"ace", 7, "**ACE**" }, {"bzip2", 0, "\x42\x5a\x68\x39\x31" }, {"gzip", 0, "\x1f\x8b"}, {"deb", 0, "!\ndebian-binary " }, {"7z", 0, "7z\xbc\xaf\x27\x1c" }/*, {"xz", 0, "\xfd\x37\x7a\x58\x5a\x00"}*/ }; int KrArcBaseManager::autoDetectElems = sizeof(autoDetectParams) / sizeof(AutoDetectParams); +const int KrArcBaseManager::maxLenType = 5; QString KrArcBaseManager::detectArchive(bool &encrypted, QString fileName, bool checkEncrypted, bool fast) { encrypted = false; QFile arcFile(fileName); if (arcFile.open(QIODevice::ReadOnly)) { char buffer[ 1024 ]; long sizeMax = arcFile.read(buffer, sizeof(buffer)); arcFile.close(); for (int i = 0; i < autoDetectElems; i++) { QByteArray detectionString = autoDetectParams[ i ].detectionString; int location = autoDetectParams[ i ].location; int endPtr = detectionString.length() + location; if (endPtr > sizeMax) continue; int j = 0; for (; j != detectionString.length(); j++) { if (detectionString[ j ] == '?') continue; if (buffer[ location + j ] != detectionString[ j ]) break; } if (j == detectionString.length()) { QString type = autoDetectParams[ i ].type; if (type == "bzip2" || type == "gzip") { if (fast) { if (fileName.endsWith(QLatin1String(".tar.gz"))) type = "tgz"; else if (fileName.endsWith(QLatin1String(".tar.bz2"))) type = "tbz"; } else { KTar tapeArchive(fileName); if (tapeArchive.open(QIODevice::ReadOnly)) { tapeArchive.close(); if (type == "gzip") type = "tgz"; else if (type == "bzip2") type = "tbz"; } } } else if (type == "zip") encrypted = (buffer[6] & 1); else if (type == "arj") { if (sizeMax > 4) { long headerSize = ((unsigned char *)buffer)[ 2 ] + 256 * ((unsigned char *)buffer)[ 3 ]; long fileHeader = headerSize + 10; if (fileHeader + 9 < sizeMax && buffer[ fileHeader ] == (char)0x60 && buffer[ fileHeader + 1 ] == (char)0xea) encrypted = (buffer[ fileHeader + 8 ] & 1); } } else if (type == "rar") { if (sizeMax > 13 && buffer[ 9 ] == (char)0x73) { if (buffer[ 10 ] & 0x80) { // the header is encrypted? encrypted = true; } else { long offset = 7; long mainHeaderSize = ((unsigned char *)buffer)[ offset+5 ] + 256 * ((unsigned char *)buffer)[ offset+6 ]; offset += mainHeaderSize; while (offset + 10 < sizeMax) { long headerSize = ((unsigned char *)buffer)[ offset+5 ] + 256 * ((unsigned char *)buffer)[ offset+6 ]; bool isDir = (buffer[ offset+7 ] == '\0') && (buffer[ offset+8 ] == '\0') && (buffer[ offset+9 ] == '\0') && (buffer[ offset+10 ] == '\0'); if (buffer[ offset + 2 ] != (char)0x74) break; if (!isDir) { encrypted = (buffer[ offset + 3 ] & 4) != 0; break; } offset += headerSize; } } } } else if (type == "ace") { long offset = 0; long mainHeaderSize = ((unsigned char *)buffer)[ offset+2 ] + 256 * ((unsigned char *)buffer)[ offset+3 ] + 4; offset += mainHeaderSize; while (offset + 10 < sizeMax) { long headerSize = ((unsigned char *)buffer)[ offset+2 ] + 256 * ((unsigned char *)buffer)[ offset+3 ] + 4; bool isDir = (buffer[ offset+11 ] == '\0') && (buffer[ offset+12 ] == '\0') && (buffer[ offset+13 ] == '\0') && (buffer[ offset+14 ] == '\0'); if (buffer[ offset + 4 ] != (char)0x01) break; if (!isDir) { encrypted = (buffer[ offset + 6 ] & 64) != 0; break; } offset += headerSize; } } else if (type == "7z") { // encryption check is expensive, check only if it's necessary if (checkEncrypted) checkIf7zIsEncrypted(encrypted, fileName); } return type; } } if (sizeMax >= 512) { /* checking if it's a tar file */ unsigned checksum = 32 * 8; char chksum[ 9 ]; for (int i = 0; i != 512; i++) checksum += ((unsigned char *)buffer)[ i ]; for (int i = 148; i != 156; i++) checksum -= ((unsigned char *)buffer)[ i ]; sprintf(chksum, "0%o", checksum); if (!memcmp(buffer + 148, chksum, strlen(chksum))) { int k = strlen(chksum); for (; k < 8; k++) if (buffer[148+k] != 0 && buffer[148+k] != 32) break; if (k == 8) return "tar"; } } } if (fileName.endsWith(QLatin1String(".tar.lzma")) || fileName.endsWith(QLatin1String(".tlz"))) { return "tlz"; } if (fileName.endsWith(QLatin1String(".lzma"))) { return "lzma"; } if (fileName.endsWith(QLatin1String(".tar.xz")) || fileName.endsWith(QLatin1String(".txz"))) { return "txz"; } if (fileName.endsWith(QLatin1String(".xz"))) { return "xz"; } return QString(); } + +//! Returns a short identifier of the type of a file, obtained from the mime type of the file +/*! + \param mime The mime type of the file. + \return A short QString which contains an identifier of the type of the file. +*/ +QString KrArcBaseManager::getShortTypeFromMime(const QString &mime) +{ + // 7zip files are a not a normal case because their mimetype does not + // follow the norm of other types: zip, tar, lha, ace, arj, etc. + if (mime == "application/x-7z-compressed") + return "7z"; + + // If it's a rar file but its mimetype isn't "application/x-rar" + if (mime == "application/x-rar-compressed") + return "rar"; + + // The short type that will be returned + QString sType = mime; + + int lastHyphen = sType.lastIndexOf('-'); + if (lastHyphen != -1) + sType = sType.mid(lastHyphen + 1); + else { + int lastSlash = sType.lastIndexOf('/'); + if (lastSlash != -1) + sType = sType.mid(lastSlash + 1); + } + // The identifier kept short + if (sType.length() > maxLenType) + sType = sType.right(maxLenType); + + return sType; +} diff --git a/krArc/krarcbasemanager.h b/krArc/krarcbasemanager.h index 0eeee1c0..95c6cc5b 100644 --- a/krArc/krarcbasemanager.h +++ b/krArc/krarcbasemanager.h @@ -1,47 +1,52 @@ /*************************************************************************** krarcbasemanager.h ------------------ copyright : (C) 2003 by Rafi Yanai & Shie Erlich email : krusader@users.sf.net web site : http://krusader.sourceforge.net ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRARCBASEMANAGER_H #define KRARCBASEMANAGER_H #include /*! * \brief An abstract base class for managing archives. */ class KrArcBaseManager { private: //! Information about a type of archive and the bytes that are used to detect it. struct AutoDetectParams { QString type; int location; QByteArray detectionString; }; static AutoDetectParams autoDetectParams[]; //! Information used to detect if a file is an archive static int autoDetectElems; //!< The size of autoDetectParams[] +protected: + //! The maximum length of a short QString that represents the type of a file + static const int maxLenType; + public: KrArcBaseManager() {} QString detectArchive(bool &, QString, bool = true, bool = false); virtual void checkIf7zIsEncrypted(bool &, QString) = 0; + static QString getShortTypeFromMime(const QString &); virtual ~KrArcBaseManager() {} }; #endif // KRARCBASEMANAGER_H diff --git a/krusader/Dialogs/checksumdlg.cpp b/krusader/Dialogs/checksumdlg.cpp index 473cd618..c907df2f 100644 --- a/krusader/Dialogs/checksumdlg.cpp +++ b/krusader/Dialogs/checksumdlg.cpp @@ -1,752 +1,754 @@ /***************************************************************************** * Copyright (C) 2005 Shie Erlich * * Copyright (C) 2007-2008 Csaba Karai * * Copyright (C) 2008 Jonas Bähr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This package is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this package; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ #include "checksumdlg.h" #include "../krusader.h" #include "../krglobal.h" #include "../GUI/krlistwidget.h" #include "../GUI/krtreewidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../krservices.h" class CS_Tool; // forward typedef void PREPARE_PROC_FUNC(KProcess& proc, CS_Tool *self, const QStringList& files, const QString checksumFile, bool recursive, const QString& type); typedef QStringList GET_FAILED_FUNC(const QStringList& stdOut, const QStringList& stdErr); class CS_Tool { public: enum Type { MD5 = 0, SHA1, SHA256, TIGER, WHIRLPOOL, SFV, CRC, SHA224, SHA384, SHA512, NumOfTypes }; Type type; QString binary; bool recursive; bool standardFormat; PREPARE_PROC_FUNC *create, *verify; GET_FAILED_FUNC *failed; }; class CS_ToolByType { public: QList tools, r_tools; // normal and recursive tools }; // handles md5sum and sha1sum void sumCreateFunc(KProcess& proc, CS_Tool *self, const QStringList& files, const QString, bool recursive, const QString&) { Q_UNUSED(recursive) proc << KrServices::fullPathName(self->binary); Q_ASSERT(!recursive); proc << files; } void sumVerifyFunc(KProcess& proc, CS_Tool *self, const QStringList& /* files */, const QString checksumFile, bool recursive, const QString& /* type */) { Q_UNUSED(recursive) proc << KrServices::fullPathName(self->binary); Q_ASSERT(!recursive); proc << "-c" << checksumFile; } QStringList sumFailedFunc(const QStringList& stdOut, const QStringList& stdErr) { // md5sum and sha1sum print "...: FAILED" for failed files and display // the number of failures to stderr. so if stderr is empty, we'll assume all is ok QStringList result; if (stdErr.size() == 0) return result; result += stdErr; // grep for the ":FAILED" substring const QString tmp = QString(": FAILED").toLocal8Bit(); for (int i = 0; i < stdOut.size();++i) { if (stdOut[i].indexOf(tmp) != -1) result += stdOut[i]; } return result; } // handles *deep binaries void deepCreateFunc(KProcess& proc, CS_Tool *self, const QStringList& files, const QString, bool recursive, const QString&) { proc << KrServices::fullPathName(self->binary); if (recursive) proc << "-r"; proc << "-l" << files; } void deepVerifyFunc(KProcess& proc, CS_Tool *self, const QStringList& files, const QString checksumFile, bool recursive, const QString&) { proc << KrServices::fullPathName(self->binary); if (recursive) proc << "-r"; proc << "-x" << checksumFile << files; } QStringList deepFailedFunc(const QStringList& stdOut, const QStringList&/* stdErr */) { // *deep dumps (via -x) all failed hashes to stdout return stdOut; } // handles cfv binary void cfvCreateFunc(KProcess& proc, CS_Tool *self, const QStringList& files, const QString, bool recursive, const QString& type) { proc << KrServices::fullPathName(self->binary) << "-C" << "-VV"; if (recursive) proc << "-rr"; proc << "-t" << type << "-f-" << "-U" << files; } void cfvVerifyFunc(KProcess& proc, CS_Tool *self, const QStringList& /* files */, const QString checksumFile, bool recursive, const QString&type) { proc << KrServices::fullPathName(self->binary) << "-M"; if (recursive) proc << "-rr"; proc << "-U" << "-VV" << "-t" << type << "-f" << checksumFile;// << files; } QStringList cfvFailedFunc(const QStringList& /* stdOut */, const QStringList& stdErr) { // cfv dumps all failed hashes to stderr return stdErr; } // important: this table should be ordered like so that all md5 tools should be // one after another, and then all sha1 and so on and so forth. they tools must be grouped, // since the code in getTools() counts on it! CS_Tool cs_tools[] = { // type binary recursive stdFmt create_func verify_func failed_func {CS_Tool::MD5, "md5sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, {CS_Tool::MD5, "md5deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, {CS_Tool::MD5, "cfv", true, true, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, {CS_Tool::SHA1, "sha1sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, {CS_Tool::SHA1, "sha1deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, {CS_Tool::SHA1, "cfv", true, true, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, {CS_Tool::SHA224, "sha224sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, {CS_Tool::SHA256, "sha256sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, {CS_Tool::SHA256, "sha256deep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, {CS_Tool::SHA384, "sha384sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, {CS_Tool::SHA512, "sha512sum", false, true, sumCreateFunc, sumVerifyFunc, sumFailedFunc}, {CS_Tool::TIGER, "tigerdeep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, {CS_Tool::WHIRLPOOL, "whirlpooldeep", true, true, deepCreateFunc, deepVerifyFunc, deepFailedFunc}, {CS_Tool::SFV, "cfv", true, false, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, {CS_Tool::CRC, "cfv", true, false, cfvCreateFunc, cfvVerifyFunc, cfvFailedFunc}, }; QMap cs_textToType; QMap cs_typeToText; void initChecksumModule() { // prepare the dictionaries - pity it has to be manually cs_textToType["md5"] = CS_Tool::MD5; cs_textToType["sha1"] = CS_Tool::SHA1; cs_textToType["sha256"] = CS_Tool::SHA256; cs_textToType["sha224"] = CS_Tool::SHA224; cs_textToType["sha384"] = CS_Tool::SHA384; cs_textToType["sha512"] = CS_Tool::SHA512; cs_textToType["tiger"] = CS_Tool::TIGER; cs_textToType["whirlpool"] = CS_Tool::WHIRLPOOL; cs_textToType["sfv"] = CS_Tool::SFV; cs_textToType["crc"] = CS_Tool::CRC; cs_typeToText[CS_Tool::MD5] = "md5"; cs_typeToText[CS_Tool::SHA1] = "sha1"; cs_typeToText[CS_Tool::SHA256] = "sha256"; cs_typeToText[CS_Tool::SHA224] = "sha224"; cs_typeToText[CS_Tool::SHA384] = "sha384"; cs_typeToText[CS_Tool::SHA512] = "sha512"; cs_typeToText[CS_Tool::TIGER] = "tiger"; cs_typeToText[CS_Tool::WHIRLPOOL] = "whirlpool"; cs_typeToText[CS_Tool::SFV] = "sfv"; cs_typeToText[CS_Tool::CRC] = "crc"; // build the checksumFilter (for usage in KRQuery) QMap::Iterator it; for (it = cs_textToType.begin(); it != cs_textToType.end(); ++it) MatchChecksumDlg::checksumTypesFilter += ("*." + it.key() + ' '); } // -------------------------------------------------- // returns a list of tools which can work with recursive or non-recursive mode and are installed // note: only 1 tool from each type is suggested static QList getTools(bool folders) { QList result; uint i; for (i = 0; i < sizeof(cs_tools) / sizeof(CS_Tool); ++i) { if (!result.isEmpty() && result.last()->type == cs_tools[i].type) continue; // 1 from each type please if (folders && !cs_tools[i].recursive) continue; if (KrServices::cmdExist(cs_tools[i].binary)) result.append(&cs_tools[i]); } return result; } // ------------- CreateChecksumDlg CreateChecksumDlg::CreateChecksumDlg(const QStringList& files, bool containFolders, const QString& path) : QDialog(krApp) { setWindowModality(Qt::WindowModal); setWindowTitle(i18n("Create Checksum")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QList tools = getTools(containFolders); if (tools.count() == 0) { // nothing was suggested?! QString error = i18n("Cannot calculate checksum since no supported tool was found. " "Please check the Dependencies page in Krusader's settings."); if (containFolders) error += i18n("Note: you have selected folders, and probably have no recursive checksum tool installed." " Krusader currently supports md5deep, sha1deep, sha256deep, tigerdeep and cfv"); KMessageBox::error(0, error); return; } QWidget * widget = new QWidget(this); QGridLayout *layout = new QGridLayout(widget); int row = 0; // title (icon+text) QHBoxLayout *hlayout = new QHBoxLayout; QLabel *p = new QLabel(widget); p->setPixmap(krLoader->loadIcon("document-edit-sign", KIconLoader::Desktop, 32)); hlayout->addWidget(p); QLabel *l1 = new QLabel(widget); if (containFolders) l1->setText(i18n("About to calculate checksum for the following files and folders:")); else l1->setText(i18n("About to calculate checksum for the following files:")); hlayout->addWidget(l1); layout->addLayout(hlayout, row, 0, 1, 2, Qt::AlignLeft); ++row; // file list KrListWidget *lb = new KrListWidget(widget); lb->addItems(files); layout->addWidget(lb, row, 0, 1, 2); ++row; // checksum method QHBoxLayout *hlayout2 = new QHBoxLayout; QLabel *l2 = new QLabel(i18n("Select the checksum method:"), widget); hlayout2->addWidget(l2); KComboBox *method = new KComboBox(widget); // -- fill the combo with available methods int i; for (i = 0; i < tools.count(); ++i) method->addItem(cs_typeToText[tools.at(i)->type], i); method->setFocus(); hlayout2->addWidget(method); layout->addLayout(hlayout2, row, 0, 1, 2, Qt::AlignLeft); ++row; mainLayout->addWidget(widget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); if (exec() != Accepted) return; // else implied: run the process QTemporaryFile tmpOut(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.stdout")); tmpOut.open(); // necessary to create the filename QTemporaryFile tmpErr(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.stderr")); tmpErr.open(); // necessary to create the filename KProcess proc; CS_Tool *mytool = tools.at(method->currentIndex()); mytool->create(proc, mytool, files, QString(), containFolders, method->currentText()); proc.setOutputChannelMode(KProcess::SeparateChannels); // without this the next 2 lines have no effect! proc.setStandardOutputFile(tmpOut.fileName()); proc.setStandardErrorFile(tmpErr.fileName()); proc.setWorkingDirectory(path); krApp->startWaiting(i18n("Calculating checksums..."), 0, true); QApplication::setOverrideCursor(Qt::WaitCursor); proc.start(); // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking // it would be better to connect to started(), error() and finished() - if (proc.waitForStarted()) while (proc.state() == QProcess::Running) { + if (proc.waitForStarted()) + while (proc.state() == QProcess::Running) { usleep(500); qApp->processEvents(); if (krApp->wasWaitingCancelled()) { // user cancelled proc.kill(); QApplication::restoreOverrideCursor(); return; } }; krApp->stopWait(); QApplication::restoreOverrideCursor(); if (proc.exitStatus() != QProcess::NormalExit) { KMessageBox::error(0, i18n("There was an error while running %1.", mytool->binary)); return; } // suggest a filename QString suggestedFilename = path + '/'; if (files.count() > 1) suggestedFilename += ("checksum." + cs_typeToText[mytool->type]); else suggestedFilename += (files[0] + '.' + cs_typeToText[mytool->type]); // send both stdout and stderr QStringList stdOut, stdErr; if (!KrServices::fileToStringList(&tmpOut, stdOut) || !KrServices::fileToStringList(&tmpErr, stdErr)) { KMessageBox::error(krApp, i18n("Error reading stdout or stderr")); return; } ChecksumResultsDlg dlg(stdOut, stdErr, suggestedFilename, mytool->standardFormat); } // ------------- MatchChecksumDlg QString MatchChecksumDlg::checksumTypesFilter; MatchChecksumDlg::MatchChecksumDlg(const QStringList& files, bool containFolders, const QString& path, const QString& checksumFile) : QDialog(krApp) { setWindowTitle(i18n("Verify Checksum")); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QList tools = getTools(containFolders); if (tools.count() == 0) { // nothing was suggested?! QString error = i18n("Cannot verify checksum since no supported tool was found. " "Please check the Dependencies page in Krusader's settings."); if (containFolders) error += i18n("Note: you have selected folders, and probably have no recursive checksum tool installed." " Krusader currently supports md5deep, sha1deep, sha256deep, tigerdeep and cfv"); KMessageBox::error(0, error); return; } QWidget * widget = new QWidget(this); QGridLayout *layout = new QGridLayout(widget); int row = 0; // title (icon+text) QHBoxLayout *hlayout = new QHBoxLayout; QLabel *p = new QLabel(widget); p->setPixmap(krLoader->loadIcon("document-edit-decrypt-verify", KIconLoader::Desktop, 32)); hlayout->addWidget(p); QLabel *l1 = new QLabel(widget); if (containFolders) l1->setText(i18n("About to verify checksum for the following files and folders:")); else l1->setText(i18n("About to verify checksum for the following files:")); hlayout->addWidget(l1); layout->addLayout(hlayout, row, 0, 1, 2, Qt::AlignLeft); ++row; // file list KrListWidget *lb = new KrListWidget(widget); lb->addItems(files); layout->addWidget(lb, row, 0, 1, 2); ++row; // checksum file QHBoxLayout *hlayout2 = new QHBoxLayout; QLabel *l2 = new QLabel(i18n("Checksum file:"), widget); hlayout2->addWidget(l2); KUrlRequester *checksumFileReq = new KUrlRequester(widget); checksumFileReq->setUrl(QUrl::fromLocalFile(path)); if (!checksumFile.isEmpty()) checksumFileReq->setUrl(QUrl::fromLocalFile(checksumFile)); checksumFileReq->setFocus(); hlayout2->addWidget(checksumFileReq); layout->addLayout(hlayout2, row, 0, 1, 2, Qt::AlignLeft); mainLayout->addWidget(widget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); if (exec() != Accepted) return; QString file = checksumFileReq->url().toDisplayString(QUrl::PreferLocalFile); QString extension; if (!verifyChecksumFile(file, extension)) { KMessageBox::error(0, i18n("Error reading checksum file %1.
Please specify a valid checksum file.
", file)); return; } // do we have a tool for that extension? int i; CS_Tool *mytool = 0; for (i = 0; i < tools.count(); ++i) if (cs_typeToText[tools.at(i)->type] == extension.toLower()) { mytool = tools.at(i); break; } if (!mytool) { KMessageBox::error(0, i18n("Krusader cannot find a checksum tool that handles %1 on your system. Please check the Dependencies page in Krusader's settings.", extension)); return; } // else implied: run the process QTemporaryFile tmpOut(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.stdout")); tmpOut.open(); // necessary to create the filename QTemporaryFile tmpErr(QDir::tempPath() + QLatin1String("/krusader_XXXXXX.stderr")); tmpErr.open(); // necessary to create the filename KProcess proc; mytool->verify(proc, mytool, files, file, containFolders, extension); proc.setOutputChannelMode(KProcess::SeparateChannels); // without this the next 2 lines have no effect! proc.setStandardOutputFile(tmpOut.fileName()); proc.setStandardErrorFile(tmpErr.fileName()); proc.setWorkingDirectory(path); krApp->startWaiting(i18n("Verifying checksums..."), 0, true); QApplication::setOverrideCursor(Qt::WaitCursor); proc.start(); // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking // it would be better to connect to started(), error() and finished() - if (proc.waitForStarted()) while (proc.state() == QProcess::Running) { + if (proc.waitForStarted()) + while (proc.state() == QProcess::Running) { usleep(500); qApp->processEvents(); if (krApp->wasWaitingCancelled()) { // user cancelled proc.kill(); QApplication::restoreOverrideCursor(); return; } }; if (proc.exitStatus() != QProcess::NormalExit) { KMessageBox::error(0, i18n("There was an error while running %1.", mytool->binary)); return; } QApplication::restoreOverrideCursor(); krApp->stopWait(); // send both stdout and stderr QStringList stdOut, stdErr; if (!KrServices::fileToStringList(&tmpOut, stdOut) || !KrServices::fileToStringList(&tmpErr, stdErr)) { KMessageBox::error(krApp, i18n("Error reading stdout or stderr")); return; } VerifyResultDlg dlg(mytool->failed(stdOut, stdErr)); } bool MatchChecksumDlg::verifyChecksumFile(QString path, QString& extension) { QFileInfo f(path); if (!f.exists() || f.isDir()) return false; // find the extension extension = path.mid(path.lastIndexOf(".") + 1); // TODO: do we know the extension? if not, ask the user for one return true; } // ------------- VerifyResultDlg VerifyResultDlg::VerifyResultDlg(const QStringList& failed) : QDialog(krApp) { setWindowTitle(i18n("Verify Checksum")); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget * widget = new QWidget(this); QGridLayout *layout = new QGridLayout(widget); bool errors = failed.size() > 0; int row = 0; // create the icon and title QHBoxLayout *hlayout = new QHBoxLayout; QLabel p(widget); p.setPixmap(krLoader->loadIcon(errors ? "dialog-error" : "dialog-information", KIconLoader::Desktop, 32)); hlayout->addWidget(&p); QLabel *l1 = new QLabel((errors ? i18n("Errors were detected while verifying the checksums") : i18n("Checksums were verified successfully")), widget); hlayout->addWidget(l1); layout->addLayout(hlayout, row, 0, 1, 2, Qt::AlignLeft); ++row; if (errors) { QLabel *l3 = new QLabel(i18n("The following files have failed:"), widget); layout->addWidget(l3, row, 0, 1, 2); ++row; KrListWidget *lb2 = new KrListWidget(widget); lb2->addItems(failed); layout->addWidget(lb2, row, 0, 1, 2); ++row; } mainLayout->addWidget(widget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); mainLayout->addWidget(buttonBox); buttonBox->button(QDialogButtonBox::Close)->setDefault(true); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); exec(); } // ------------- ChecksumResultsDlg ChecksumResultsDlg::ChecksumResultsDlg(const QStringList &stdOut, const QStringList &stdErr, const QString& suggestedFilename, bool standardFormat) : QDialog(krApp), _onePerFile(0), _checksumFileSelector(0), _data(stdOut), _suggestedFilename(suggestedFilename) { // md5 tools display errors into stderr, so we'll use that to determine the result of the job bool errors = stdErr.size() > 0; bool successes = stdOut.size() > 0; setWindowTitle(i18n("Create Checksum")); setWindowModality(Qt::WindowModal); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget * widget = new QWidget(this); QGridLayout *layout = new QGridLayout(widget); int row = 0; // create the icon and title QHBoxLayout *hlayout = new QHBoxLayout; QLabel p(widget); p.setPixmap(krLoader->loadIcon(errors || !successes ? "dialog-error" : "dialog-information", KIconLoader::Desktop, 32)); hlayout->addWidget(&p); QLabel *l1 = new QLabel((errors || !successes ? i18n("Errors were detected while creating the checksums") : i18n("Checksums were created successfully")), widget); hlayout->addWidget(l1); layout->addLayout(hlayout, row, 0, 1, 2, Qt::AlignLeft); ++row; if (successes) { if (errors) { QLabel *l2 = new QLabel(i18n("Here are the calculated checksums:"), widget); layout->addWidget(l2, row, 0, 1, 2); ++row; } KrTreeWidget *lv = new KrTreeWidget(widget); QStringList columns; if (standardFormat) { columns << i18n("Hash"); columns << i18n("File"); lv->setAllColumnsShowFocus(true); } else { columns << i18n("File and hash"); } lv->setHeaderLabels(columns); for (QStringList::ConstIterator it = stdOut.begin(); it != stdOut.end(); ++it) { QString line = (*it); if (standardFormat) { int space = line.indexOf(' '); QTreeWidgetItem * item = new QTreeWidgetItem(lv); item->setText(0, line.left(space)); item->setText(1, line.mid(space + 2)); } else { QTreeWidgetItem * item = new QTreeWidgetItem(lv); item->setText(0, line); } } lv->sortItems(standardFormat ? 1 : 0, Qt::AscendingOrder); layout->addWidget(lv, row, 0, 1, 2); ++row; } if (errors) { QFrame *line1 = new QFrame(widget); line1->setGeometry(QRect(60, 210, 501, 20)); line1->setFrameShape(QFrame::HLine); line1->setFrameShadow(QFrame::Sunken); layout->addWidget(line1, row, 0, 1, 2); ++row; QLabel *l3 = new QLabel(i18n("Here are the errors received:"), widget); layout->addWidget(l3, row, 0, 1, 2); ++row; KrListWidget *lb = new KrListWidget(widget); lb->addItems(stdErr); layout->addWidget(lb, row, 0, 1, 2); ++row; } // save checksum to disk, if any hashes are found if (successes) { QHBoxLayout *hlayout2 = new QHBoxLayout; QLabel *label = new QLabel(i18n("Save checksum to file:"), widget); hlayout2->addWidget(label); _checksumFileSelector = new KUrlRequester(QUrl::fromLocalFile(suggestedFilename), widget); hlayout2->addWidget(_checksumFileSelector, Qt::AlignLeft); layout->addLayout(hlayout2, row, 0, 1, 2, Qt::AlignLeft); ++row; _checksumFileSelector->setFocus(); } if (stdOut.size() > 1 && standardFormat) { _onePerFile = new QCheckBox(i18n("Checksum file for each source file"), widget); _onePerFile->setChecked(false); connect(_onePerFile, SIGNAL(toggled(bool)), _checksumFileSelector, SLOT(setDisabled(bool))); layout->addWidget(_onePerFile, row, 0, 1, 2, Qt::AlignLeft); ++row; } mainLayout->addWidget(widget); QDialogButtonBox *buttonBox; if (successes) { buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); } else { buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); buttonBox->button(QDialogButtonBox::Close)->setDefault(true); } mainLayout->addWidget(buttonBox); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); exec(); } void ChecksumResultsDlg::accept() { if (_onePerFile && _onePerFile->isChecked()) { Q_ASSERT(_data.size() > 1); if (savePerFile()) QDialog::accept(); } else if (!_checksumFileSelector->url().isEmpty()) { if (saveChecksum(_data, _checksumFileSelector->url().toDisplayString(QUrl::PreferLocalFile))) QDialog::accept(); } } bool ChecksumResultsDlg::saveChecksum(const QStringList& data, QString filename) { if (QFile::exists(filename) && KMessageBox::warningContinueCancel(this, i18n("File %1 already exists.\nAre you sure you want to overwrite it?", filename), i18n("Warning"), KGuiItem(i18n("Overwrite"))) != KMessageBox::Continue) { // find a better name to save to filename = QFileDialog::getSaveFileName(0, i18n("Select a file to save to"), QString(), QStringLiteral("*")); if (filename.simplified().isEmpty()) return false; } QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); for (QStringList::ConstIterator it = data.constBegin(); it != data.constEnd(); ++it) stream << *it << "\n"; file.close(); } if (file.error() != QFile::NoError) { KMessageBox::detailedError(this, i18n("Error saving file %1", filename), file.errorString()); return false; } else return true; } bool ChecksumResultsDlg::savePerFile() { QString type = _suggestedFilename.mid(_suggestedFilename.lastIndexOf('.')); krApp->startWaiting(i18n("Saving checksum files..."), 0); for (QStringList::ConstIterator it = _data.constBegin(); it != _data.constEnd(); ++it) { QString line = (*it); QString filename = line.mid(line.indexOf(' ') + 2) + type; QStringList l; l << line; if (!saveChecksum(l, filename)) { KMessageBox::error(this, i18n("Errors occurred while saving multiple checksums. Stopping")); krApp->stopWait(); return false; } } krApp->stopWait(); return true; } diff --git a/krusader/Search/krsearchmod.cpp b/krusader/Search/krsearchmod.cpp index 442ada0c..cc13fc95 100644 --- a/krusader/Search/krsearchmod.cpp +++ b/krusader/Search/krsearchmod.cpp @@ -1,242 +1,242 @@ /*************************************************************************** krsearchmod.cpp ------------------- copyright : (C) 2001 by Shie Erlich & Rafi Yanai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krsearchmod.h" #include #include #include #include #include #include #include #include "../VFS/krquery.h" #include "../VFS/vfile.h" #include "../VFS/krpermhandler.h" #include "../VFS/krarchandler.h" #define EVENT_PROCESS_DELAY 250 extern KRarcHandler arcHandler; KRSearchMod::KRSearchMod(const KRQuery* q) { stopSearch = false; /// ===> added query = new KRQuery(*q); connect(query, SIGNAL(status(const QString &)), this, SIGNAL(searching(const QString&))); connect(query, SIGNAL(processEvents(bool &)), this, SLOT(slotProcessEvents(bool &))); remote_vfs = 0; virtual_vfs = 0; } KRSearchMod::~KRSearchMod() { delete query; if (remote_vfs) delete remote_vfs; if (virtual_vfs) delete virtual_vfs; } void KRSearchMod::start() { unScannedUrls.clear(); scannedUrls.clear(); timer.start(); QList whereToSearch = query->searchInDirs(); // search every dir that needs to be searched for (int i = 0; i < whereToSearch.count(); ++i) scanURL(whereToSearch [ i ]); emit finished(); } void KRSearchMod::stop() { stopSearch = true; } void KRSearchMod::scanURL(QUrl url) { if (stopSearch) return; unScannedUrls.push(url); while (!unScannedUrls.isEmpty()) { QUrl urlToCheck = unScannedUrls.pop(); if (stopSearch) return; if (query->isExcluded(urlToCheck)) { if (!query->searchInDirs().contains(urlToCheck)) continue; } if (scannedUrls.contains(urlToCheck)) continue; scannedUrls.push(urlToCheck); emit searching(urlToCheck.toDisplayString(QUrl::PreferLocalFile)); if (urlToCheck.isLocalFile()) scanLocalDir(urlToCheck); else scanRemoteDir(urlToCheck); } } void KRSearchMod::scanLocalDir(QUrl urlToScan) { QString dir = vfs::ensureTrailingSlash(urlToScan).path(); QT_DIR* d = QT_OPENDIR(dir.toLocal8Bit()); if (!d) return ; QT_DIRENT* dirEnt; while ((dirEnt = QT_READDIR(d)) != NULL) { QString name = QString::fromLocal8Bit(dirEnt->d_name); // we don't scan the ".",".." enteries if (name == "." || name == "..") continue; QT_STATBUF stat_p; QT_LSTAT((dir + name).toLocal8Bit(), &stat_p); QUrl url = QUrl::fromLocalFile(dir + name); QString mime; if (query->searchInArchives() || !query->hasMimeType()) { QMimeDatabase db; QMimeType mt = db.mimeTypeForUrl(url); if (mt.isValid()) mime = mt.name(); } // creating a vfile object for matching with krquery vfile * vf = new vfile(name, (KIO::filesize_t)stat_p.st_size, KRpermHandler::mode2QString(stat_p.st_mode), stat_p.st_mtime, S_ISLNK(stat_p.st_mode), false/*FIXME*/, stat_p.st_uid, stat_p.st_gid, mime, "", stat_p.st_mode); vf->vfile_setUrl(url); if (query->isRecursive()) { if (S_ISLNK(stat_p.st_mode) && query->followLinks()) unScannedUrls.push(QUrl::fromLocalFile(QDir(dir + name).canonicalPath())); else if (S_ISDIR(stat_p.st_mode)) unScannedUrls.push(url); } if (query->searchInArchives()) { if (KRarcHandler::arcSupported(mime)) { QUrl archiveURL = url; bool encrypted; QString realType = arcHandler.getType(encrypted, url.path(), mime); if (!encrypted) { - if (realType == "-tbz" || realType == "-tgz" || realType == "tarz" || realType == "-tar" || realType == "-tlz") + if (realType == "tbz" || realType == "tgz" || realType == "tarz" || realType == "tar" || realType == "tlz") archiveURL.setScheme("tar"); else archiveURL.setScheme("krarc"); unScannedUrls.push(archiveURL); } } } if (query->match(vf)) { // if we got here - we got a winner results.append(dir + name); emit found(name, dir, (KIO::filesize_t) stat_p.st_size, stat_p.st_mtime, KRpermHandler::mode2QString(stat_p.st_mode), stat_p.st_uid, stat_p.st_gid, query->foundText()); } delete vf; if (timer.elapsed() >= EVENT_PROCESS_DELAY) { qApp->processEvents(); timer.start(); if (stopSearch) return; } } // clean up QT_CLOSEDIR(d); } void KRSearchMod::scanRemoteDir(QUrl url) { vfs * vfs_; if (url.scheme() == QStringLiteral("virt")) { if (virtual_vfs == 0) virtual_vfs = new virt_vfs(0); vfs_ = virtual_vfs; } else { if (remote_vfs == 0) remote_vfs = new ftp_vfs(0); vfs_ = remote_vfs; } if (!vfs_->vfs_refresh(url)) return ; for (vfile * vf = vfs_->vfs_getFirstFile(); vf != 0 ; vf = vfs_->vfs_getNextFile()) { QString name = vf->vfile_getName(); QUrl fileURL = vfs_->vfs_getFile(name); if (query->isRecursive() && ((vf->vfile_isSymLink() && query->followLinks()) || vf->vfile_isDir())) unScannedUrls.push(fileURL); if (query->match(vf)) { // if we got here - we got a winner results.append(fileURL.toDisplayString(QUrl::PreferLocalFile)); emit found(fileURL.fileName(), KIO::upUrl(fileURL).toDisplayString(QUrl::PreferLocalFile | QUrl::StripTrailingSlash), vf->vfile_getSize(), vf->vfile_getTime_t(), vf->vfile_getPerm(), vf->vfile_getUid(), vf->vfile_getGid(), query->foundText()); } if (timer.elapsed() >= EVENT_PROCESS_DELAY) { qApp->processEvents(); timer.start(); if (stopSearch) return; } } } void KRSearchMod::slotProcessEvents(bool & stopped) { qApp->processEvents(); stopped = stopSearch; } diff --git a/krusader/VFS/krarchandler.cpp b/krusader/VFS/krarchandler.cpp index 1a95cd8a..e7385fbc 100644 --- a/krusader/VFS/krarchandler.cpp +++ b/krusader/VFS/krarchandler.cpp @@ -1,712 +1,708 @@ /*************************************************************************** krarchandler.cpp ------------------- copyright : (C) 2001 by Shie Erlich & Rafi Yanai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krarchandler.h" #include #include #include #include #include #include #include #include #include #include #include #include "../krglobal.h" #include "../defaults.h" #include "../krservices.h" #include "../Dialogs/krpleasewait.h" #if 0 class DefaultKRarcObserver : public KRarcObserver { public: DefaultKRarcObserver() {} virtual ~DefaultKRarcObserver() {} virtual void processEvents() Q_DECL_OVERRIDE { usleep(1000); qApp->processEvents(); } virtual void subJobStarted(const QString & jobTitle, int count) Q_DECL_OVERRIDE { krApp->startWaiting(jobTitle, count, true); } virtual void subJobStopped() Q_DECL_OVERRIDE { krApp->stopWait(); } virtual bool wasCancelled() Q_DECL_OVERRIDE { return krApp->wasWaitingCancelled(); } virtual void error(const QString & error) Q_DECL_OVERRIDE { KMessageBox::error(krApp, error, i18n("Error")); } virtual void detailedError(const QString & error, const QString & details) Q_DECL_OVERRIDE { KMessageBox::detailedError(krApp, error, details, i18n("Error")); } virtual void incrementProgress(int c) Q_DECL_OVERRIDE { krApp->plzWait->incProgress(c); } }; #endif static QStringList arcProtocols = QString("tar;bzip;bzip2;lzma;xz;gzip;krarc;zip").split(';'); KWallet::Wallet * KRarcHandler::wallet = 0; QStringList KRarcHandler::supportedPackers() { QStringList packers; // we will simply try to find the packers here.. if (KrServices::cmdExist("tar")) packers.append("tar"); if (KrServices::cmdExist("gzip")) packers.append("gzip"); if (KrServices::cmdExist("bzip2")) packers.append("bzip2"); if (KrServices::cmdExist("lzma")) packers.append("lzma"); if (KrServices::cmdExist("xz")) packers.append("xz"); if (KrServices::cmdExist("unzip")) packers.append("unzip"); if (KrServices::cmdExist("zip")) packers.append("zip"); if (KrServices::cmdExist("zip")) packers.append("cbz"); if (KrServices::cmdExist("lha")) packers.append("lha"); if (KrServices::cmdExist("cpio")) packers.append("cpio"); if (KrServices::cmdExist("unrar")) packers.append("unrar"); if (KrServices::cmdExist("rar")) packers.append("rar"); if (KrServices::cmdExist("rar")) packers.append("cbr"); if (KrServices::cmdExist("arj")) packers.append("arj"); if (KrServices::cmdExist("unarj")) packers.append("unarj"); if (KrServices::cmdExist("unace")) packers.append("unace"); if (KrServices::cmdExist("dpkg")) packers.append("dpkg"); if (KrServices::cmdExist("7z") || KrServices::cmdExist("7za")) packers.append("7z"); if (KrServices::cmdExist("rpm") && KrServices::cmdExist("rpm2cpio")) packers.append("rpm"); // qDebug() << "Supported Packers:" << endl; //QStringList::Iterator it; //for( it = packers.begin(); it != packers.end(); ++it ) // qDebug() << *it << endl; return packers; } bool KRarcHandler::arcSupported(QString type) { // lst will contain the supported unpacker list... KConfigGroup group(krConfig, "Archives"); QStringList lst = group.readEntry("Supported Packers", QStringList()); - // Normalize the type of the file - if (type.length() > 4) { - // 7zip files are a not a normal case because their mimetype does not - // follow the norm of other types: zip, tar, lha, ace, arj, etc. - if (type == "application/x-7z-compressed") - type = "-7z"; - else - // If it's a rar file but its mimetype isn't "application/x-rar" - if (type == "application/x-rar-compressed") - type = "-rar"; - else - type = type.right(4); + // Let's notice that in some cases the QString `type` that arrives here + // represents a mimetype, and in some other cases it represents + // a short identifier. + // If `type` is not a short identifier then it's supposed that `type` is a mime type + if (type.length() > maxLenType) { + type = getShortTypeFromMime(type); } - if ((type == "-zip" || type == "/zip") && lst.contains("unzip")) + if ((type == "zip" || type == "/zip") && lst.contains("unzip")) return true; - else if (type == "-tar" && lst.contains("tar")) + else if (type == "tar" && lst.contains("tar")) return true; - else if (type == "-tbz" && lst.contains("tar")) + else if (type == "tbz" && lst.contains("tar")) return true; - else if (type == "-tgz" && lst.contains("tar")) + else if (type == "tgz" && lst.contains("tar")) return true; - else if (type == "-tlz" && lst.contains("tar")) + else if (type == "tlz" && lst.contains("tar")) return true; - else if (type == "-txz" && lst.contains("tar")) + else if (type == "txz" && lst.contains("tar")) return true; else if (type == "tarz" && lst.contains("tar")) return true; else if (type == "gzip" && lst.contains("gzip")) return true; - else if (type == "zip2" && lst.contains("bzip2")) + else if (type == "bzip2" && lst.contains("bzip2")) return true; else if (type == "lzma" && lst.contains("lzma")) return true; - else if (type == "-xz" && lst.contains("xz")) + else if (type == "xz" && lst.contains("xz")) return true; - else if (type == "-lha" && lst.contains("lha")) + else if (type == "lha" && lst.contains("lha")) return true; - else if (type == "-ace" && lst.contains("unace")) + else if (type == "ace" && lst.contains("unace")) return true; - else if (type == "-rpm" && lst.contains("cpio")) + else if (type == "rpm" && lst.contains("cpio")) return true; else if (type == "cpio" && lst.contains("cpio")) return true; - else if (type == "-rar" && (lst.contains("unrar") || lst.contains("rar"))) + else if (type == "rar" && (lst.contains("unrar") || lst.contains("rar"))) return true; - else if (type == "-arj" && (lst.contains("unarj") || lst.contains("arj"))) + else if (type == "arj" && (lst.contains("unarj") || lst.contains("arj"))) return true; - else if (type == "-deb" && (lst.contains("dpkg") && lst.contains("tar"))) + else if (type == "deb" && (lst.contains("dpkg") && lst.contains("tar"))) return true; - else if (type == "-7z" && lst.contains("7z")) + else if (type == "7z" && lst.contains("7z")) return true; - // not supported : ( + // not supported return false; } long KRarcHandler::arcFileCount(QString archive, QString type, QString password, KRarcObserver *observer) { int divideWith = 1; // first check if supported - if (!arcSupported(type)) return 0; + if (!arcSupported(type)) + return 0; - // bzip an gzip archive contains only one file - if (type == "zip2" || type == "gzip" || type == "lzma" || type == "-xz") return 1L; + // bzip2, gzip, etc. archives contain only one file + if (type == "bzip2" || type == "gzip" || type == "lzma" || type == "xz") + return 1L; // set the right lister to do the job QStringList lister; - if (type == "-zip") lister << KrServices::fullPathName("unzip") << "-ZTs"; - else if (type == "-tar") lister << KrServices::fullPathName("tar") << "-tvf"; - else if (type == "-tgz") lister << KrServices::fullPathName("tar") << "-tvzf"; + if (type == "zip") lister << KrServices::fullPathName("unzip") << "-ZTs"; + else if (type == "tar") lister << KrServices::fullPathName("tar") << "-tvf"; + else if (type == "tgz") lister << KrServices::fullPathName("tar") << "-tvzf"; else if (type == "tarz") lister << KrServices::fullPathName("tar") << "-tvzf"; - else if (type == "-tbz") lister << KrServices::fullPathName("tar") << "-tjvf"; - else if (type == "-tlz") lister << KrServices::fullPathName("tar") << "--lzma" << "-tvf"; - else if (type == "-txz") lister << KrServices::fullPathName("tar") << "--xz" << "-tvf"; - else if (type == "-lha") lister << KrServices::fullPathName("lha") << "l"; - else if (type == "-rar") lister << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "l" << "-v"; - else if (type == "-ace") lister << KrServices::fullPathName("unace") << "l"; - else if (type == "-arj") { + else if (type == "tbz") lister << KrServices::fullPathName("tar") << "-tjvf"; + else if (type == "tlz") lister << KrServices::fullPathName("tar") << "--lzma" << "-tvf"; + else if (type == "txz") lister << KrServices::fullPathName("tar") << "--xz" << "-tvf"; + else if (type == "lha") lister << KrServices::fullPathName("lha") << "l"; + else if (type == "rar") lister << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "l" << "-v"; + else if (type == "ace") lister << KrServices::fullPathName("unace") << "l"; + else if (type == "arj") { if (KrServices::cmdExist("arj")) lister << KrServices::fullPathName("arj") << "v" << "-y" << "-v", divideWith = 4; else lister << KrServices::fullPathName("unarj") << "l"; - } else if (type == "-rpm") lister << KrServices::fullPathName("rpm") << "--dump" << "-lpq"; - else if (type == "-deb") lister << KrServices::fullPathName("dpkg") << "-c"; - else if (type == "-7z") lister << KrServices::fullPathName("7z") << "-y" << "l"; + } else if (type == "rpm") lister << KrServices::fullPathName("rpm") << "--dump" << "-lpq"; + else if (type == "deb") lister << KrServices::fullPathName("dpkg") << "-c"; + else if (type == "7z") lister << KrServices::fullPathName("7z") << "-y" << "l"; else return 0L; if (!password.isNull()) { - if (type == "-arj") + if (type == "arj") lister << QString("-g%1").arg(password); - if (type == "-ace" || type == "-rar" || type == "-7z") + if (type == "ace" || type == "rar" || type == "7z") lister << QString("-p%1").arg(password); } // tell the user to wait observer->subJobStarted(i18n("Counting files in archive"), 0); // count the number of files in the archive long count = 1; KProcess list; list << lister << archive; - if (type == "-ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! + if (type == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! list.setStandardInputFile("/dev/ptmx"); list.setOutputChannelMode(KProcess::SeparateChannels); // without this output redirection has no effect list.start(); // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking // it would be better to connect to started(), error() and finished() if (list.waitForStarted()) while (list.state() == QProcess::Running) { observer->processEvents(); if (observer->wasCancelled()) list.kill(); } ; // busy wait - need to find something better... observer->subJobStopped(); if (list.exitStatus() != QProcess::NormalExit || !checkStatus(type, list.exitCode())) { observer->detailedError(i18n("Failed to list the content of the archive (%1).", archive), QString::fromLocal8Bit(list.readAllStandardError())); return 0; } count = list.readAllStandardOutput().count('\n'); //make sure you call stopWait after this function return... // observer->subJobStopped(); return count / divideWith; } bool KRarcHandler::unpack(QString archive, QString type, QString password, QString dest, KRarcObserver *observer) { KConfigGroup group(krConfig, "Archives"); if (group.readEntry("Test Before Unpack", _TestBeforeUnpack)) { // test first - or be sorry later... - if (type != "-rpm" && type != "-deb" && !test(archive, type, password, observer, 0)) { + if (type != "rpm" && type != "deb" && !test(archive, type, password, observer, 0)) { observer->error(i18n("Failed to unpack %1.", archive)); return false; } } // count the files in the archive long count = arcFileCount(archive, type, password, observer); - if (count == 0) return false; // not supported - if (count == 1) count = 0 ; + if (count == 0) + return false; // not supported + if (count == 1) + count = 0; // choose the right packer for the job QString cpioName; QStringList packer; // set the right packer to do the job - if (type == "-zip") packer << KrServices::fullPathName("unzip") << "-o" ; - else if (type == "-tar") packer << KrServices::fullPathName("tar") << "-xvf"; - else if (type == "-tgz") packer << KrServices::fullPathName("tar") << "-xvzf"; + if (type == "zip") packer << KrServices::fullPathName("unzip") << "-o" ; + else if (type == "tar") packer << KrServices::fullPathName("tar") << "-xvf"; + else if (type == "tgz") packer << KrServices::fullPathName("tar") << "-xvzf"; else if (type == "tarz") packer << KrServices::fullPathName("tar") << "-xvzf"; - else if (type == "-tbz") packer << KrServices::fullPathName("tar") << "-xjvf"; - else if (type == "-tlz") packer << KrServices::fullPathName("tar") << "--lzma" << "-xvf"; - else if (type == "-txz") packer << KrServices::fullPathName("tar") << "--xz" << "-xvf"; + else if (type == "tbz") packer << KrServices::fullPathName("tar") << "-xjvf"; + else if (type == "tlz") packer << KrServices::fullPathName("tar") << "--lzma" << "-xvf"; + else if (type == "txz") packer << KrServices::fullPathName("tar") << "--xz" << "-xvf"; else if (type == "gzip") packer << KrServices::fullPathName("gzip") << "-cd"; - else if (type == "zip2") packer << KrServices::fullPathName("bzip2") << "-cdk"; + else if (type == "bzip2") packer << KrServices::fullPathName("bzip2") << "-cdk"; else if (type == "lzma") packer << KrServices::fullPathName("lzma") << "-cdk"; - else if (type == "-xz") packer << KrServices::fullPathName("xz") << "-cdk"; - else if (type == "-lha") packer << KrServices::fullPathName("lha") << "xf"; - else if (type == "-rar") packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "-y" << "x"; - else if (type == "-ace") packer << KrServices::fullPathName("unace") << "x"; - else if (type == "-arj") { + else if (type == "xz") packer << KrServices::fullPathName("xz") << "-cdk"; + else if (type == "lha") packer << KrServices::fullPathName("lha") << "xf"; + else if (type == "rar") packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "-y" << "x"; + else if (type == "ace") packer << KrServices::fullPathName("unace") << "x"; + else if (type == "arj") { if (KrServices::cmdExist("arj")) packer << KrServices::fullPathName("arj") << "-y" << "-v" << "x"; else packer << KrServices::fullPathName("unarj") << "x"; - } else if (type == "-7z") packer << KrServices::fullPathName("7z") << "-y" << "x"; - else if (type == "-rpm") { + } else if (type == "7z") packer << KrServices::fullPathName("7z") << "-y" << "x"; + else if (type == "rpm") { // TODO use QTemporaryFile (setAutoRemove(false) when asynchrone) cpioName = QDir::tempPath() + QStringLiteral("/contents.cpio"); KrLinecountingProcess cpio; cpio << KrServices::fullPathName("rpm2cpio") << archive; cpio.setStandardOutputFile(cpioName); // TODO maybe no tmpfile but a pipe (setStandardOutputProcess(packer)) cpio.start(); if (!cpio.waitForFinished() || cpio.exitStatus() != QProcess::NormalExit || !checkStatus("cpio", cpio.exitCode())) { observer->detailedError(i18n("Failed to convert rpm (%1) to cpio.", archive), cpio.getErrorMsg()); return 0; } archive = cpioName; packer << KrServices::fullPathName("cpio") << "--force-local" << "--no-absolute-filenames" << "-iuvdF"; - } else if (type == "-deb") { + } else if (type == "deb") { // TODO use QTemporaryFile (setAutoRemove(false) when asynchrone) cpioName = QDir::tempPath() + QStringLiteral("/contents.tar"); KrLinecountingProcess dpkg; dpkg << KrServices::fullPathName("dpkg") << "--fsys-tarfile" << archive; dpkg.setStandardOutputFile(cpioName); // TODO maybe no tmpfile but a pipe (setStandardOutputProcess(packer)) dpkg.start(); - if (!dpkg.waitForFinished() || dpkg.exitStatus() != QProcess::NormalExit || !checkStatus("-deb", dpkg.exitCode())) { + if (!dpkg.waitForFinished() || dpkg.exitStatus() != QProcess::NormalExit || !checkStatus("deb", dpkg.exitCode())) { observer->detailedError(i18n("Failed to convert deb (%1) to tar.", archive), dpkg.getErrorMsg()); return 0; } archive = cpioName; packer << KrServices::fullPathName("tar") << "xvf"; } else return false; if (!password.isNull()) { - if (type == "-zip") + if (type == "zip") packer << "-P" << password; - if (type == "-arj") + if (type == "arj") packer << QString("-g%1").arg(password); - if (type == "-ace" || type == "-rar" || type == "-7z") + if (type == "ace" || type == "rar" || type == "7z") packer << QString("-p%1").arg(password); } // unpack the files KrLinecountingProcess proc; proc << packer << archive; - if (type == "zip2" || type == "gzip" || type == "lzma" || type == "-xz") { + if (type == "bzip2" || type == "gzip" || type == "lzma" || type == "xz") { QString arcname = archive.mid(archive.lastIndexOf("/") + 1); if (arcname.contains(".")) arcname = arcname.left(arcname.lastIndexOf(".")); - proc.setStandardOutputFile(dest + '/' + arcname); + proc.setStandardOutputFile(dest + '/' + arcname); } - if (type == "-ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! + if (type == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! proc.setStandardInputFile("/dev/ptmx"); proc.setWorkingDirectory(dest); // tell the user to wait observer->subJobStarted(i18n("Unpacking File(s)"), count); if (count != 0) { connect(&proc, SIGNAL(newOutputLines(int)), observer, SLOT(incrementProgress(int))); - if (type == "-rpm") + if (type == "rpm") connect(&proc, SIGNAL(newErrorLines(int)), observer, SLOT(incrementProgress(int))); } // start the unpacking process proc.start(); // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking // it would be better to connect to started(), error() and finished() - if (proc.waitForStarted()) while (proc.state() == QProcess::Running) { + if (proc.waitForStarted()) + while (proc.state() == QProcess::Running) { observer->processEvents(); if (observer->wasCancelled()) proc.kill(); } ; // busy wait - need to find something better... observer->subJobStopped(); if (!cpioName.isEmpty()) QFile(cpioName).remove(); /* remove the cpio file */ // check the return value if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) { observer->detailedError(i18n("Failed to unpack %1.", archive), observer->wasCancelled() ? i18n("User cancelled.") : proc.getErrorMsg()); return false; } return true; // SUCCESS } bool KRarcHandler::test(QString archive, QString type, QString password, KRarcObserver *observer, long count) { // choose the right packer for the job QStringList packer; // set the right packer to do the job - if (type == "-zip") packer << KrServices::fullPathName("unzip") << "-t"; - else if (type == "-tar") packer << KrServices::fullPathName("tar") << "-tvf"; - else if (type == "-tgz") packer << KrServices::fullPathName("tar") << "-tvzf"; + if (type == "zip") packer << KrServices::fullPathName("unzip") << "-t"; + else if (type == "tar") packer << KrServices::fullPathName("tar") << "-tvf"; + else if (type == "tgz") packer << KrServices::fullPathName("tar") << "-tvzf"; else if (type == "tarz") packer << KrServices::fullPathName("tar") << "-tvzf"; - else if (type == "-tbz") packer << KrServices::fullPathName("tar") << "-tjvf"; - else if (type == "-tlz") packer << KrServices::fullPathName("tar") << "--lzma" << "-tvf"; - else if (type == "-txz") packer << KrServices::fullPathName("tar") << "--xz" << "-tvf"; + else if (type == "tbz") packer << KrServices::fullPathName("tar") << "-tjvf"; + else if (type == "tlz") packer << KrServices::fullPathName("tar") << "--lzma" << "-tvf"; + else if (type == "txz") packer << KrServices::fullPathName("tar") << "--xz" << "-tvf"; else if (type == "gzip") packer << KrServices::fullPathName("gzip") << "-tv"; - else if (type == "zip2") packer << KrServices::fullPathName("bzip2") << "-tv"; + else if (type == "bzip2") packer << KrServices::fullPathName("bzip2") << "-tv"; else if (type == "lzma") packer << KrServices::fullPathName("lzma") << "-tv"; - else if (type == "-xz") packer << KrServices::fullPathName("xz") << "-tv"; - else if (type == "-rar") packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "t"; - else if (type == "-ace") packer << KrServices::fullPathName("unace") << "t"; - else if (type == "-lha") packer << KrServices::fullPathName("lha") << "t"; - else if (type == "-arj") packer << KrServices::fullPathName(KrServices::cmdExist("arj") ? "arj" : "unarj") << "t"; + else if (type == "xz") packer << KrServices::fullPathName("xz") << "-tv"; + else if (type == "rar") packer << KrServices::fullPathName(KrServices::cmdExist("rar") ? "rar" : "unrar") << "t"; + else if (type == "ace") packer << KrServices::fullPathName("unace") << "t"; + else if (type == "lha") packer << KrServices::fullPathName("lha") << "t"; + else if (type == "arj") packer << KrServices::fullPathName(KrServices::cmdExist("arj") ? "arj" : "unarj") << "t"; else if (type == "cpio") packer << KrServices::fullPathName("cpio") << "--only-verify-crc" << "-tvF"; - else if (type == "-7z") packer << KrServices::fullPathName("7z") << "-y" << "t"; + else if (type == "7z") packer << KrServices::fullPathName("7z") << "-y" << "t"; else return false; if (!password.isNull()) { - if (type == "-zip") + if (type == "zip") packer << "-P" << password; - if (type == "-arj") + if (type == "arj") packer << QString("-g%1").arg(password); - if (type == "-ace" || type == "-rar" || type == "-7z") + if (type == "ace" || type == "rar" || type == "7z") packer << QString("-p%1").arg(password); } // unpack the files KrLinecountingProcess proc; proc << packer << archive; - if (type == "-ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! + if (type == "ace" && QFile("/dev/ptmx").exists()) // Don't remove, unace crashes if missing!!! proc.setStandardInputFile("/dev/ptmx"); // tell the user to wait observer->subJobStarted(i18n("Testing Archive"), count); if (count != 0) connect(&proc, SIGNAL(newOutputLines(int)), observer, SLOT(incrementProgress(int))); // start the unpacking process proc.start(); // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking // it would be better to connect to started(), error() and finished() - if (proc.waitForStarted()) while (proc.state() == QProcess::Running) { + if (proc.waitForStarted()) + while (proc.state() == QProcess::Running) { observer->processEvents(); if (observer->wasCancelled()) proc.kill(); } ; // busy wait - need to find something better... observer->subJobStopped(); // check the return value if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) return false; return true; // SUCCESS } bool KRarcHandler::pack(QStringList fileNames, QString type, QString dest, long count, QMap extraProps, KRarcObserver *observer) { // set the right packer to do the job QStringList packer; if (type == "zip") { - packer << KrServices::fullPathName("zip") << "-ry"; type = "-zip"; + packer << KrServices::fullPathName("zip") << "-ry"; } else if (type == "cbz") { - packer << KrServices::fullPathName("zip") << "-ry"; type = "-zip"; + packer << KrServices::fullPathName("zip") << "-ry"; + type = "zip"; } else if (type == "tar") { - packer << KrServices::fullPathName("tar") << "-cvf"; type = "-tar"; + packer << KrServices::fullPathName("tar") << "-cvf"; } else if (type == "tar.gz") { - packer << KrServices::fullPathName("tar") << "-cvzf"; type = "-tgz"; + packer << KrServices::fullPathName("tar") << "-cvzf"; + type = "tgz"; } else if (type == "tar.bz2") { - packer << KrServices::fullPathName("tar") << "-cvjf"; type = "-tbz"; + packer << KrServices::fullPathName("tar") << "-cvjf"; + type = "tbz"; } else if (type == "tar.lzma") { - packer << KrServices::fullPathName("tar") << "--lzma" << "-cvf"; type = "-tlz"; + packer << KrServices::fullPathName("tar") << "--lzma" << "-cvf"; + type = "tlz"; } else if (type == "tar.xz") { - packer << KrServices::fullPathName("tar") << "--xz" << "-cvf"; type = "-txz"; + packer << KrServices::fullPathName("tar") << "--xz" << "-cvf"; + type = "txz"; } else if (type == "rar") { - packer << KrServices::fullPathName("rar") << "-r" << "a"; type = "-rar"; + packer << KrServices::fullPathName("rar") << "-r" << "a"; } else if (type == "cbr") { - packer << KrServices::fullPathName("rar") << "-r" << "a"; type = "-rar"; + packer << KrServices::fullPathName("rar") << "-r" << "a"; + type = "rar"; } else if (type == "lha") { - packer << KrServices::fullPathName("lha") << "a"; type = "-lha"; + packer << KrServices::fullPathName("lha") << "a"; } else if (type == "arj") { - packer << KrServices::fullPathName("arj") << "-r" << "-y" << "a"; type = "-arj"; + packer << KrServices::fullPathName("arj") << "-r" << "-y" << "a"; } else if (type == "7z") { - packer << KrServices::fullPathName("7z") << "-y" << "a"; type = "-7z"; + packer << KrServices::fullPathName("7z") << "-y" << "a"; } else return false; QString password; if (extraProps.count("Password") > 0) { password = extraProps[ "Password" ]; if (!password.isNull()) { - if (type == "-zip") + if (type == "zip") packer << "-P" << password; - else if (type == "-arj") + else if (type == "arj") packer << QString("-g%1").arg(password); - else if (type == "-ace" || type == "-7z") + else if (type == "ace" || type == "7z") packer << QString("-p%1").arg(password); - else if (type == "-rar") { + else if (type == "rar") { if (extraProps.count("EncryptHeaders") > 0) packer << QString("-hp%1").arg(password); else packer << QString("-p%1").arg(password); } else password.clear(); } } if (extraProps.count("VolumeSize") > 0) { QString sizeStr = extraProps[ "VolumeSize" ]; KIO::filesize_t size = sizeStr.toLongLong(); if (size >= 10000) { - if (type == "-arj" || type == "-rar") + if (type == "arj" || type == "rar") packer << QString("-v%1b").arg(sizeStr); } } if (extraProps.count("CompressionLevel") > 0) { int level = extraProps[ "CompressionLevel" ].toInt() - 1; if (level < 0) level = 0; if (level > 8) level = 8; - if (type == "-rar") { + if (type == "rar") { static const int rarLevels[] = { 0, 1, 2, 2, 3, 3, 4, 4, 5 }; packer << QString("-m%1").arg(rarLevels[ level ]); - } else if (type == "-arj") { + } else if (type == "arj") { static const int arjLevels[] = { 0, 4, 4, 3, 3, 2, 2, 1, 1 }; packer << QString("-m%1").arg(arjLevels[ level ]); - } else if (type == "-zip") { + } else if (type == "zip") { static const int zipLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 }; packer << QString("-%1").arg(zipLevels[ level ]); - } else if (type == "-7z") { + } else if (type == "7z") { static const int sevenZipLevels[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9 }; packer << QString("-mx%1").arg(sevenZipLevels[ level ]); } } if (extraProps.count("CommandLineSwitches") > 0) packer << QString("%1").arg(extraProps[ "CommandLineSwitches" ]); // prepare to pack KrLinecountingProcess proc; proc << packer << dest; for (QStringList::Iterator file = fileNames.begin(); file != fileNames.end(); ++file) { proc << *file; } // tell the user to wait observer->subJobStarted(i18n("Packing File(s)"), count); if (count != 0) connect(&proc, SIGNAL(newOutputLines(int)), observer, SLOT(incrementProgress(int))); // start the packing process proc.start(); // TODO make use of asynchronous process starting. waitForStarted(int msec = 30000) is blocking // it would be better to connect to started(), error() and finished() - if (proc.waitForStarted()) while (proc.state() == QProcess::Running) { + if (proc.waitForStarted()) + while (proc.state() == QProcess::Running) { observer->processEvents(); if (observer->wasCancelled()) proc.kill(); } ; // busy wait - need to find something better... observer->subJobStopped(); // check the return value if (proc.exitStatus() != QProcess::NormalExit || !checkStatus(type, proc.exitCode())) { observer->detailedError(i18n("Failed to pack %1.", dest), observer->wasCancelled() ? i18n("User cancelled.") : proc.getErrorMsg()); return false; } KConfigGroup group(krConfig, "Archives"); if (group.readEntry("Test Archives", _TestArchives) && !test(dest, type, password, observer, count)) { observer->error(i18n("Failed to pack %1.", dest)); return false; } return true; // SUCCESS } bool KRarcHandler::openWallet() { if (!wallet) { // find a suitable parent window QWidget *actWindow = QApplication::activeWindow(); if (!actWindow) actWindow = (QWidget*) QApplication::desktop(); wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), actWindow->effectiveWinId()); } return (wallet != 0); } QString KRarcHandler::getPassword(QString path) { QString password; QString key = "krarc-" + path; if (!KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder(), key)) { if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet()) && wallet != 0) { delete wallet; wallet = 0; } if (openWallet() && wallet->hasFolder(KWallet::Wallet::PasswordFolder())) { wallet->setFolder(KWallet::Wallet::PasswordFolder()); QMap map; if (wallet->readMap(key, map) == 0) { QMap::const_iterator it = map.constFind("password"); if (it != map.constEnd()) password = it.value(); } } } bool keep = true; QString user = "archive"; QPointer passDlg = new KPasswordDialog(0L, KPasswordDialog::ShowKeepPassword); passDlg->setPrompt(i18n("This archive is encrypted, please supply the password:") ), passDlg->setUsername(user); passDlg->setPassword(password); if (passDlg->exec() == KPasswordDialog::Accepted) { password = passDlg->password(); if (keep) { if (!KWallet::Wallet::isOpen(KWallet::Wallet::NetworkWallet()) && wallet != 0) { delete wallet; wallet = 0; } if (openWallet()) { bool ok = true; if (!wallet->hasFolder(KWallet::Wallet::PasswordFolder())) ok = wallet->createFolder(KWallet::Wallet::PasswordFolder()); if (ok) { wallet->setFolder(KWallet::Wallet::PasswordFolder()); QMap map; map.insert("login", "archive"); map.insert("password", password); wallet->writeMap(key, map); } } } delete passDlg; return password; } delete passDlg; return ""; } bool KRarcHandler::isArchive(const QUrl &url) { QString protocol = url.scheme(); if (arcProtocols.indexOf(protocol) != -1) return true; else return false; } QString KRarcHandler::getType(bool &encrypted, QString fileName, QString mime, bool checkEncrypted, bool fast) { QString result = detectArchive(encrypted, fileName, checkEncrypted, fast); if (result.isNull()) { - result = mime; - } else { - result = '-' + result; - } - - if (result.endsWith(QLatin1String("-7z"))) { - result = "-7z"; + // Then the type is based on the mime type + return getShortTypeFromMime(mime); } - - if (result.endsWith(QLatin1String("-xz"))) { - result = "-xz"; - } - - return result.right(4); + return result; } - bool KRarcHandler::checkStatus(QString type, int exitCode) { // if this code is changed, the code of kio_krarcProtocol::checkStatus() must be reviewed - if (type == "-zip" || type == "-rar" || type == "-7z") + if (type == "zip" || type == "rar" || type == "7z") return exitCode == 0 || exitCode == 1; - else if (type == "-ace" || type == "zip2" || type == "-lha" || type == "-rpm" || type == "cpio" || - type == "-tar" || type == "tarz" || type == "-tbz" || type == "-tgz" || type == "-arj" || - type == "-deb" || type == "-tlz" || type == "-txz") + else if (type == "ace" || type == "bzip2" || type == "lha" || type == "rpm" || type == "cpio" || + type == "tar" || type == "tarz" || type == "tbz" || type == "tgz" || type == "arj" || + type == "deb" || type == "tlz" || type == "txz") return exitCode == 0; - else if (type == "gzip" || type == "lzma" || type == "-xz") + else if (type == "gzip" || type == "lzma" || type == "xz") return exitCode == 0 || exitCode == 2; else return exitCode == 0; } void KRarcHandler::checkIf7zIsEncrypted(bool &encrypted, QString fileName) { Kr7zEncryptionChecker proc; // TODO incorporate all this in Kr7zEncryptionChecker proc << KrServices::fullPathName("7z") << "-y" << "t"; proc << fileName; proc.start(); proc.waitForFinished(); encrypted = proc.isEncrypted(); } diff --git a/krusader/VFS/krarchandler.h b/krusader/VFS/krarchandler.h index 6b780247..5bbcca82 100644 --- a/krusader/VFS/krarchandler.h +++ b/krusader/VFS/krarchandler.h @@ -1,96 +1,97 @@ /*************************************************************************** krarchandler.h ------------------- copyright : (C) 2001 by Shie Erlich & Rafi Yanai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description: this class will supply static archive handling functions. *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRARCHANDLER_H #define KRARCHANDLER_H #include #include #include #include #include "../../krArc/krarcbasemanager.h" #include "../../krArc/krlinecountingprocess.h" #include "kr7zencryptionchecker.h" namespace KWallet { class Wallet; } class KRarcObserver : public QObject { Q_OBJECT public: virtual ~KRarcObserver() {} virtual void processEvents() = 0; virtual void subJobStarted(const QString & jobTitle, int count) = 0; virtual void subJobStopped() = 0; virtual bool wasCancelled() = 0; virtual void error(const QString & error) = 0; virtual void detailedError(const QString & error, const QString & details) = 0; public slots: virtual void incrementProgress(int) = 0; }; class KRarcHandler: public QObject, public KrArcBaseManager { Q_OBJECT public: // return the number of files in the archive static long arcFileCount(QString archive, QString type, QString password, KRarcObserver *observer); // unpack an archive to destination directory static bool unpack(QString archive, QString type, QString password, QString dest, KRarcObserver *observer ); // pack an archive to destination directory static bool pack(QStringList fileNames, QString type, QString dest, long count, QMap extraProps, KRarcObserver *observer ); // test an archive static bool test(QString archive, QString type, QString password, KRarcObserver *observer, long count = 0L ); // returns `true` if the right unpacker exist in the system static bool arcSupported(QString type); // return the list of supported packers static QStringList supportedPackers(); // returns `true` if the url is an archive (ie: tar:/home/test/file.tar.bz2) static bool isArchive(const QUrl &url); // used to determine the type of the archive QString getType(bool &encrypted, QString fileName, QString mime, bool checkEncrypted = true, bool fast = false); // queries the password from the user static QString getPassword(QString path); // detects the archive type void checkIf7zIsEncrypted(bool &, QString); private: // checks if the returned status is correct static bool checkStatus(QString type, int exitCode); + static bool openWallet(); static KWallet::Wallet * wallet; }; #endif