/* * Copyright (C) 2022 Ivailo Monev * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libarchivehandler.h" #include "kerfuffle/kerfuffle_export.h" #include "kerfuffle/queries.h" #include #include #include #include #include #include static void copyEntry(ArchiveEntry *archiveentry, const KArchiveEntry *karchiveentry) { archiveentry->insert(FileName, karchiveentry->pathname); archiveentry->insert(InternalID, karchiveentry->pathname); archiveentry->insert(Size, qlonglong(karchiveentry->size)); archiveentry->insert(IsDirectory, S_ISDIR(karchiveentry->mode)); archiveentry->insert(Permissions, ReadWriteArchiveInterface::permissionsString(karchiveentry->mode)); archiveentry->insert(Owner, karchiveentry->username); archiveentry->insert(Group, karchiveentry->groupname); archiveentry->insert(Timestamp, QDateTime::fromTime_t(karchiveentry->mtime)); archiveentry->insert(IsPasswordProtected, karchiveentry->encrypted); if (!karchiveentry->symlink.isEmpty()) { archiveentry->insert(Link, karchiveentry->symlink); } } LibArchiveInterface::LibArchiveInterface(QObject *parent, const QVariantList &args) : ReadWriteArchiveInterface(parent, args) { } LibArchiveInterface::~LibArchiveInterface() { } bool LibArchiveInterface::list() { KArchive karchive(filename()); if (!karchive.isReadable()) { emit error(i18nc("@info", "Could not open the archive %1: %2.", filename(), karchive.errorString())); return false; } emit progress(0.1); foreach (const KArchiveEntry &karchiveentry, karchive.list()) { ArchiveEntry archiveentry; copyEntry(&archiveentry, &karchiveentry); emit entry(archiveentry); } emit progress(1.0); return true; } bool LibArchiveInterface::copyFiles(const QVariantList& files, const QString &destinationDirectory, ExtractionOptions options) { const bool extractAll = files.isEmpty(); const bool preservePaths = options.value(QLatin1String("PreservePaths")).toBool(); KArchive karchive(filename()); if (!karchive.isReadable()) { emit error(i18nc("@info", "Could not open the archive %1: %2.", filename(), karchive.errorString())); return false; } if (karchive.requiresPassphrase()) { PasswordNeededQuery passwordquery(filename()); emit userQuery(&passwordquery); passwordquery.waitForResponse(); if (passwordquery.responseCancelled()) { return false; } karchive.setReadPassphrase(passwordquery.password()); } QStringList fileslist; if (extractAll) { foreach (const KArchiveEntry &karchiveentry, karchive.list()) { fileslist.append(QFile::decodeName(karchiveentry.pathname)); } } else { fileslist.reserve(files.size()); foreach (const QVariant &variant, files) { fileslist.append(variant.toString()); } } bool autoskip = false; QStringList::iterator it = fileslist.begin(); while (it != fileslist.end()) { const QString fullpath = destinationDirectory + QLatin1Char('/') + (*it); if (QFile::exists(fullpath)) { if (autoskip) { it = fileslist.erase(it); it++; continue; } Kerfuffle::OverwriteQuery overwritequery(fullpath); overwritequery.setNoRenameMode(true); emit userQuery(&overwritequery); overwritequery.waitForResponse(); if (overwritequery.responseCancelled()) { return false; } else if (overwritequery.responseOverwriteAll()) { // KArchive will overwrite break; } else if (overwritequery.responseOverwrite()) { it++; continue; } else if (overwritequery.responseRename()) { Q_ASSERT(false); } else if (overwritequery.responseSkip()) { it = fileslist.erase(it); continue; } else if (overwritequery.responseAutoSkip()) { autoskip = true; it = fileslist.erase(it); } } it++; } connect(&karchive, SIGNAL(progress(qreal)), this, SLOT(emitProgress(qreal))); if (!karchive.extract(fileslist, destinationDirectory, preservePaths)) { emit error(karchive.errorString()); return false; } return true; } bool LibArchiveInterface::addFiles(const QStringList &files, const CompressionOptions &options) { const QString globalWorkDir = options.value(QLatin1String("GlobalWorkDir")).toString(); if (!globalWorkDir.isEmpty()) { kDebug() << "GlobalWorkDir is set, changing dir to" << globalWorkDir; QDir::setCurrent(globalWorkDir); } QString rootNode = options.value(QLatin1String("RootNode"), QVariant()).toString(); if (!rootNode.isEmpty() && !rootNode.endsWith(QLatin1Char('/'))) { rootNode.append(QLatin1Char('/')); } KArchive karchive(filename()); if (!karchive.isWritable()) { emit error(i18nc("@info", "Could not open the archive %1: %2.", filename(), karchive.errorString())); return false; } if (karchive.requiresPassphrase()) { emit error(i18nc("@info", "Writing password-protected archives is not supported.")); return false; } if (!globalWorkDir.isEmpty()) { const QString tempprefix(QDir::cleanPath(globalWorkDir) + QDir::separator() + QLatin1String("ark-")); kDebug() << "GlobalWorkDir is set, setting temporary prefix to" << tempprefix; karchive.setTempPrefix(tempprefix); } const QList oldEntries = karchive.list(); const QString strip(QDir::cleanPath(globalWorkDir) + QDir::separator()); connect(&karchive, SIGNAL(progress(qreal)), this, SLOT(emitProgress(qreal))); if (!karchive.add(files, QFile::encodeName(strip), QFile::encodeName(rootNode))) { emit error(karchive.errorString()); return false; } foreach (const KArchiveEntry &karchiveentry, karchive.list()) { if (!oldEntries.contains(karchiveentry)) { ArchiveEntry archiveentry; copyEntry(&archiveentry, &karchiveentry); emit entry(archiveentry); } } return true; } bool LibArchiveInterface::deleteFiles(const QVariantList &files) { KArchive karchive(filename()); if (!karchive.isWritable()) { emit error(i18nc("@info", "Could not open the archive %1: %2.", filename(), karchive.errorString())); return false; } if (karchive.requiresPassphrase()) { emit error(i18nc("@info", "Writing password-protected archives is not supported.")); return false; } QStringList fileslist; fileslist.reserve(files.size()); foreach (const QVariant &variant, files) { fileslist.append(variant.toString()); } connect(&karchive, SIGNAL(progress(qreal)), this, SLOT(emitProgress(qreal))); if (!karchive.remove(fileslist)) { emit error(karchive.errorString()); return false; } foreach (const QString &file, fileslist) { emit entryRemoved(file); } return true; } bool LibArchiveInterface::isReadOnly() const { KArchive karchive(filename()); return !karchive.isWritable(); } void LibArchiveInterface::emitProgress(const qreal value) { emit progress(value); } KERFUFFLE_EXPORT_PLUGIN(LibArchiveInterface) #include "moc_libarchivehandler.cpp"