/* * ark -- archiver for the KDE project * * Copyright (C) 2007 Henrique Pinto * * 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 program 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "karchiveplugin.h" #include "kerfuffle/queries.h" #include #include #include #include #include #include #include #include #include KArchiveInterface::KArchiveInterface(QObject *parent, const QVariantList &args) : ReadWriteArchiveInterface(parent, args), m_archive(0) { kDebug(); } KArchiveInterface::~KArchiveInterface() { delete m_archive; m_archive = 0; } KArchive *KArchiveInterface::archive() { if (m_archive == 0) { KMimeType::Ptr mimeType = KMimeType::findByPath(filename()); if (mimeType->is(QLatin1String("application/zip"))) { m_archive = new KZip(filename()); } else { m_archive = new KTar(filename()); } } return m_archive; } bool KArchiveInterface::list() { kDebug(); if (!archive()->isOpen() && !archive()->open(QIODevice::ReadOnly)) { emit error(i18nc("@info", "Could not open the archive %1 for reading", filename())); return false; } else { return browseArchive(archive()); } } void KArchiveInterface::getAllEntries(const KArchiveDirectory *dir, const QString &prefix, QList< QVariant > &list) { foreach(const QString &entryName, dir->entries()) { const KArchiveEntry *entry = dir->entry(entryName); if (entry->isDirectory()) { QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName; getAllEntries(static_cast(entry), newPrefix, list); } else { list.append(prefix + QLatin1Char('/') + entryName); } } } bool KArchiveInterface::copyFiles(const QList &files, const QString &destinationDirectory, ExtractionOptions options) { const bool preservePaths = options.value(QLatin1String("PreservePaths")).toBool(); const KArchiveDirectory *dir = archive()->directory(); if (!archive()->isOpen() && !archive()->open(QIODevice::ReadOnly)) { emit error(i18nc("@info", "Could not open the archive %1 for reading", filename())); return false; } QList extrFiles = files; if (extrFiles.isEmpty()) { // All files should be extracted getAllEntries(dir, QString(), extrFiles); } bool overwriteAllSelected = false; bool autoSkipSelected = false; QSet dirCache; foreach(const QVariant &file, extrFiles) { QString realDestination = destinationDirectory; const KArchiveEntry *archiveEntry = dir->entry(file.toString()); if (!archiveEntry) { emit error(i18nc("@info", "File %1 not found in the archive" , file.toString())); return false; } if (preservePaths) { QFileInfo fi(file.toString()); QDir dest(destinationDirectory); QString filepath = archiveEntry->isDirectory() ? fi.filePath() : fi.path(); if (!dirCache.contains(filepath)) { if (!dest.mkpath(filepath)) { emit error(i18nc("@info", "Error creating directory %1", filepath)); return false; } dirCache << filepath; } realDestination = dest.absolutePath() + QLatin1Char('/') + filepath; } // TODO: handle errors, copyTo fails silently if (!archiveEntry->isDirectory()) { // We don't need to do anything about directories if (QFile::exists(realDestination + QLatin1Char('/') + archiveEntry->name()) && !overwriteAllSelected) { if (autoSkipSelected) { continue; } int response = handleFileExistsMessage(realDestination, archiveEntry->name()); if (response == OverwriteCancel) { break; } if (response == OverwriteYes || response == OverwriteAll) { static_cast(archiveEntry)->copyTo(realDestination); if (response == OverwriteAll) { overwriteAllSelected = true; } } if (response == OverwriteAutoSkip) { autoSkipSelected = true; } } else { static_cast(archiveEntry)->copyTo(realDestination); } } } return true; } int KArchiveInterface::handleFileExistsMessage(const QString &dir, const QString &fileName) { Kerfuffle::OverwriteQuery query(dir + QLatin1Char('/') + fileName); query.setNoRenameMode(true); emit userQuery(&query); query.waitForResponse(); if (query.responseOverwrite()) { return OverwriteYes; } else if (query.responseSkip()) { return OverwriteSkip; } else if (query.responseOverwriteAll()) { return OverwriteAll; } else if (query.responseAutoSkip()) { return OverwriteAutoSkip; } return OverwriteCancel; } bool KArchiveInterface::browseArchive(KArchive *archive) { return processDir(archive->directory()); } bool KArchiveInterface::processDir(const KArchiveDirectory *dir, const QString & prefix) { foreach(const QString& entryName, dir->entries()) { const KArchiveEntry *entry = dir->entry(entryName); createEntryFor(entry, prefix); if (entry->isDirectory()) { QString newPrefix = (prefix.isEmpty() ? prefix : prefix + QLatin1Char('/')) + entryName; processDir(static_cast(entry), newPrefix); } } return true; } void KArchiveInterface::createEntryFor(const KArchiveEntry *aentry, const QString& prefix) { ArchiveEntry e; QString fileName = prefix.isEmpty() ? aentry->name() : prefix + QLatin1Char('/') + aentry->name(); if (aentry->isDirectory() && !fileName.endsWith(QLatin1Char('/'))) fileName += QLatin1Char('/'); e[ FileName ] = fileName; e[ InternalID ] = e[ FileName ]; e[ Permissions ] = ReadWriteArchiveInterface::permissionsString(aentry->permissions()); e[ Owner ] = aentry->user(); e[ Group ] = aentry->group(); e[ IsDirectory ] = aentry->isDirectory(); e[ Timestamp ] = aentry->datetime(); if (!aentry->symLinkTarget().isEmpty()) { e[ Link ] = aentry->symLinkTarget(); } if (aentry->isFile()) { e[ Size ] = static_cast(aentry)->size(); } else { e[ Size ] = 0; } emit entry(e); } bool KArchiveInterface::addFiles(const QStringList &files, const Kerfuffle::CompressionOptions &options) { Q_UNUSED(options) kDebug() << "Starting..."; // delete m_archive; // m_archive = 0; if (archive()->isOpen()) { archive()->close(); } if (!archive()->open(QIODevice::ReadWrite)) { emit error(i18nc("@info", "Could not open the archive %1 for writing.", filename())); return false; } kDebug() << "Archive opened for writing..."; kDebug() << "Will add " << files.count() << " files"; foreach(const QString &path, files) { kDebug() << "Adding " << path; QFileInfo fi(path); Q_ASSERT(fi.exists()); if (fi.isDir()) { if (archive()->addLocalDirectory(path, fi.fileName())) { const KArchiveEntry *entry = archive()->directory()->entry(fi.fileName()); createEntryFor(entry, QString()); processDir((KArchiveDirectory*) archive()->directory()->entry(fi.fileName()), fi.fileName()); } else { emit error(i18nc("@info", "Could not add the directory %1 to the archive", path)); return false; } } else { if (archive()->addLocalFile(path, fi.fileName())) { const KArchiveEntry *entry = archive()->directory()->entry(fi.fileName()); createEntryFor(entry, QString()); } else { emit error(i18nc("@info", "Could not add the file %1 to the archive.", path)); return false; } } } kDebug() << "Closing the archive"; archive()->close(); kDebug() << "Done"; return true; } bool KArchiveInterface::deleteFiles(const QList & files) { Q_UNUSED(files) return false; } KERFUFFLE_EXPORT_PLUGIN(KArchiveInterface)