From 9885a0dc4db1a21f4094285e7b98dd01de2b810e Mon Sep 17 00:00:00 2001 From: Tsu Jan Date: Fri, 8 Mar 2019 03:45:32 +0330 Subject: [PATCH] Fixed an issue in file removal with 7z archives It was probably caused by a problem in 7z. Also, don't update the tree unnecessarily. --- ChangeLog | 3 ++ NEWS | 2 +- backends.cpp | 46 ++++++++++++++-------------- backends.h | 2 +- data/translations/arqiver.ts | 54 ++++++++++++++++----------------- data/translations/arqiver_eo.ts | 54 ++++++++++++++++----------------- data/translations/arqiver_nl.ts | 54 ++++++++++++++++----------------- data/translations/arqiver_pl.ts | 54 ++++++++++++++++----------------- mainWin.cpp | 46 ++++++++++++++++++++++------ mainWin.h | 1 + 10 files changed, 173 insertions(+), 143 deletions(-) diff --git a/ChangeLog b/ChangeLog index 969d4bb..1e76829 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ V0.2.0 * With tar/bsdtar and if the parent dir exists, change the parent dir name instead of extracting in a child dir. * A root archive file may mean a parent directory or a single file. Previously, it was supposed to be a parent directory and that caused single files not to be extracted with non-Gzip archives when they were present in the extraction directory. * If a file comes after its containing folder in the command line, bsdtar doesn't extract the folder. A workaround is added for this behavior. + * Prevent tree collapse after extracting an rpm archive. + * Don't update the tree unnecessarily. + * Fixed a bug in removal of encrypted files inside 7z archives. V0.1.0 --------- diff --git a/NEWS b/NEWS index 8958ce8..3e87b2b 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ Latest version: - 7 Mar 2019, V0.2.0 + 8 Mar 2019, V0.2.0 See "ChangeLog" for changes. diff --git a/backends.cpp b/backends.cpp index abd7506..ca52aee 100644 --- a/backends.cpp +++ b/backends.cpp @@ -37,11 +37,11 @@ namespace Arqiver { Backend::Backend(QObject *parent) : QObject(parent) { - PROC.setProcessChannelMode(QProcess::MergedChannels); - connect(&PROC, QOverload::of(&QProcess::finished), this, &Backend::procFinished); - connect(&PROC, &QProcess::readyReadStandardOutput, this, &Backend::processData); - connect(&PROC, &QProcess::started, this, &Backend::processStarting); - connect(&PROC, &QProcess::errorOccurred, this, &Backend::onError); + proc_.setProcessChannelMode(QProcess::MergedChannels); + connect(&proc_, QOverload::of(&QProcess::finished), this, &Backend::procFinished); + connect(&proc_, &QProcess::readyReadStandardOutput, this, &Backend::processData); + connect(&proc_, &QProcess::started, this, &Backend::processStarting); + connect(&proc_, &QProcess::errorOccurred, this, &Backend::onError); LIST = false; isGzip_ = is7z_ = false; starting7z_ = encryptionQueried_ = encrypted_ = encryptedList_ = false; @@ -138,7 +138,7 @@ QString Backend::currentFile() { } bool Backend::isWorking(){ - return (PROC.state() != QProcess::Running); + return (proc_.state() != QProcess::Running); } QStringList Backend::hierarchy() { @@ -246,7 +246,7 @@ void Backend::startAdd(QStringList& paths, bool absolutePaths) { args << "a" << fileArgs_ << paths; starting7z_ = true; keyArgs_ << "a"; - PROC.start ("7z", args); + proc_.start ("7z", args); return; } /* NOTE: All paths should have the same parent directory. @@ -280,7 +280,7 @@ void Backend::startAdd(QStringList& paths, bool absolutePaths) { args << "@" + filepath_; } keyArgs_ << "-c" << "-a" << "-C"; - PROC.start(TAR_CMD, args); + proc_.start(TAR_CMD, args); } void Backend::startRemove(QStringList& paths) { @@ -293,12 +293,12 @@ void Backend::startRemove(QStringList& paths) { paths.removeDuplicates(); QStringList args; if (is7z_) { - if (encryptedList_) - args << "-p" + pswrd_; // we had the password to open the archive + if (encrypted_) + args << "-p" + pswrd_; args << "d" << fileArgs_ << paths; starting7z_ = true; keyArgs_ << "d"; - PROC.start("7z", args); + proc_.start("7z", args); return; } args << "-c" << "-a"; @@ -310,7 +310,7 @@ void Backend::startRemove(QStringList& paths) { } args << "@" + filepath_; keyArgs_ << "-c" << "-a" << "--exclude"; - PROC.start(TAR_CMD, args); + proc_.start(TAR_CMD, args); } void Backend::startExtract(const QString& path, const QString& file, bool overwrite, bool preservePaths) { @@ -323,7 +323,7 @@ void Backend::startExtract(const QString& path, const QStringList& files, bool o /* if the extraction takes place in the same directory, we could do it in the usual way but the standard output method works in all cases */ /*if (0 && path == filepath_.section("/", 0, -2)) { - PROC.start("gzip", QStringList() << "-d" << "-k" << filepath_); + proc_.start("gzip", QStringList() << "-d" << "-k" << filepath_); return; }*/ emit processStarting(); @@ -429,14 +429,14 @@ void Backend::startExtract(const QString& path, const QStringList& files, bool o if(is7z_) { args << "-o" + xPath; - PROC.start("7z", args); + proc_.start("7z", args); } else { args << "-C" << xPath; if (archiveRootExists && contents_.size() > 1) args << "--strip-components" << "1"; // the parent name is changed keyArgs_ << "-C"; - PROC.start(TAR_CMD, args); // doesn't create xPath if not existing + proc_.start(TAR_CMD, args); // doesn't create xPath if not existing } } @@ -703,7 +703,7 @@ void Backend::startList(bool withPassword) { LIST = true; if (isGzip_) { keyArgs_ << "-l"; - PROC.start("gzip", QStringList() << "-l" << filepath_); + proc_.start("gzip", QStringList() << "-l" << filepath_); } else if (is7z_) { QStringList args; @@ -713,13 +713,13 @@ void Backend::startList(bool withPassword) { args << "l"; starting7z_ = true; keyArgs_ << "l"; - PROC.start("7z", QStringList() << args << fileArgs_); + proc_.start("7z", QStringList() << args << fileArgs_); } else { QStringList args; args << "-tv"; keyArgs_ << "-tv"; - PROC.start(TAR_CMD, QStringList() << args << fileArgs_); + proc_.start(TAR_CMD, QStringList() << args << fileArgs_); } } @@ -736,7 +736,7 @@ void Backend::procFinished(int retcode, QProcess::ExitStatus) { args << "l"; starting7z_ = true; keyArgs_.clear(); keyArgs_ << "l"; - PROC.start("7z", QStringList() << args << fileArgs_); + proc_.start("7z", QStringList() << args << fileArgs_); } return; } @@ -773,7 +773,7 @@ void Backend::procFinished(int retcode, QProcess::ExitStatus) { } else { // extraction /*if (retcode == 0) { - QStringList args = PROC.arguments(); + QStringList args = proc_.arguments(); for (int i = 0; i < args.length(); i++) { if(args[i].startsWith("-o")) //just extracted to a dir - open it now QProcess::startDetached("xdg-open \"" + args[i].section("-o", 1, -1) + "\""); @@ -861,7 +861,7 @@ void Backend::procFinished(int retcode, QProcess::ExitStatus) { void Backend::processData() { if (is7z_ && !encryptionQueried_) { if (!encryptedList_) { - QString read = PROC.readAllStandardOutput(); + QString read = proc_.readAllStandardOutput(); if (read.contains("\nERROR: ")) { // ERROR: FILE_PATH : Can not open encrypted archive. Wrong password? encryptedList_ = encrypted_ = true; } @@ -888,7 +888,7 @@ void Backend::processData() { return; // no listing here } static QString data; - QString read = data + PROC.readAllStandardOutput(); + QString read = data + proc_.readAllStandardOutput(); if (read.endsWith("\n")) data.clear(); else { @@ -923,7 +923,7 @@ void Backend::processData() { void Backend::onError(QProcess::ProcessError error) { if (error == QProcess::FailedToStart) emit errorMsg(tr("%1 is missing from your system.\nPlease install it for this kind of archive!") - .arg(PROC.program())); + .arg(proc_.program())); } } diff --git a/backends.h b/backends.h index 7c06957..44dd025 100644 --- a/backends.h +++ b/backends.h @@ -106,7 +106,7 @@ private slots: private: void parseLines(QStringList& lines); - QProcess PROC; + QProcess proc_; QString filepath_, tmpfilepath_, arqiverDir_; QStringList fileArgs_; diff --git a/data/translations/arqiver.ts b/data/translations/arqiver.ts index 71d3d46..5ca943c 100644 --- a/data/translations/arqiver.ts +++ b/data/translations/arqiver.ts @@ -357,7 +357,7 @@ Please install it for this kind of archive! - + Question @@ -387,102 +387,102 @@ Please install it for this kind of archive! - - + + Adding Items... - + Removing Items... - - - - - + + + + + Extracting... - + View Current Item - - + + Enter Password - + Cancel - + OK - + Encrypt the file list - + This will take effect after files/folders are added. - - + + Extract Into Directory - + Some files will be overwritten. Do you want to continue? - + Link To: %1 - + A simple Qt archive manager - + based on libarchive, gzip and 7z - + Author - + aka. - - + + About Arqiver - + Translators diff --git a/data/translations/arqiver_eo.ts b/data/translations/arqiver_eo.ts index 634966c..e2e1248 100644 --- a/data/translations/arqiver_eo.ts +++ b/data/translations/arqiver_eo.ts @@ -358,7 +358,7 @@ Bonvole insatlu ĝin por ĉi tia arkivo! - + Question Demando @@ -389,64 +389,64 @@ Bonvole insatlu ĝin por ĉi tia arkivo! - - + + Adding Items... Aldoni Erojn... - + Removing Items... Forviŝi Erojn... - - - - - + + + + + Extracting... Ekstrakti... - + View Current Item Vidi Ĉi Tiun Eron - - + + Enter Password Enmetu Pasvorton - + Cancel Rezigni - + OK Bone - + Encrypt the file list Ĉifri la dosierliston - + This will take effect after files/folders are added. Ĉi tio efektiviĝos post dosieroj/dosierujoj estas aldonitaj. - - + + Extract Into Directory Ekstrakto en Dosierujon - + Some files will be overwritten. Do you want to continue? @@ -455,38 +455,38 @@ Do you want to continue? - + Link To: %1 Ligilo Al %1 - + A simple Qt archive manager Simpla Qt-Arkivilo - + based on libarchive, gzip and 7z bazita sur libarchive, gzip kaj 7z - + Author Verkinto - + aka. akk. - - + + About Arqiver Pri Arqiver - + Translators Tradukintoj diff --git a/data/translations/arqiver_nl.ts b/data/translations/arqiver_nl.ts index ce497d8..6336344 100644 --- a/data/translations/arqiver_nl.ts +++ b/data/translations/arqiver_nl.ts @@ -358,7 +358,7 @@ Installeer het om dit soort archieven te kunnen beheren! - + Question Vraag @@ -389,102 +389,102 @@ Installeer het om dit soort archieven te kunnen beheren! - - + + Adding Items... Bezig met toevoegen van items... - + Removing Items... Bezig met verwijderen van items... - - - - - + + + + + Extracting... Bezig met uitpakken... - + View Current Item Huidig item tonen - - + + Enter Password Voer wachtwoord in - + Cancel Annuleren - + OK Oké - + Encrypt the file list Bestandslijst versleutelen - + This will take effect after files/folders are added. Dit wordt toegepast na het toevoegen van bestanden/mappen. - - + + Extract Into Directory Uitpakken naar map - + Some files will be overwritten. Do you want to continue? - + Link To: %1 Link naar: %1 - + A simple Qt archive manager Een eenvoudige Qt-archiefbeheerder - + based on libarchive, gzip and 7z gebaseerd op libarchive, gzip en 7z - + Author Maker - + aka. ook bekend als - - + + About Arqiver Over Arqiver - + Translators Vertalers diff --git a/data/translations/arqiver_pl.ts b/data/translations/arqiver_pl.ts index 1479d24..68142bd 100644 --- a/data/translations/arqiver_pl.ts +++ b/data/translations/arqiver_pl.ts @@ -358,7 +358,7 @@ Zainstaluj ten pakiet, aby obsługiwać ten rodzaj archiwów! - + Question Pytanie @@ -389,102 +389,102 @@ Zainstaluj ten pakiet, aby obsługiwać ten rodzaj archiwów! - - + + Adding Items... Dodawanie elementów… - + Removing Items... Usuwanie elementów… - - - - - + + + + + Extracting... Rozpakowywanie… - + View Current Item Pokaż obecny element - - + + Enter Password Wprowadź hasło - + Cancel Anuluj - + OK OK - + Encrypt the file list Szyfruj listę plików - + This will take effect after files/folders are added. Efekt będzie widoczny po dodaniu nowych plików/katalogów. - - + + Extract Into Directory Rozpakuj do katalogu - + Some files will be overwritten. Do you want to continue? - + Link To: %1 Odnośnik do: %1 - + A simple Qt archive manager Prosty menedżer archiwum Qt - + based on libarchive, gzip and 7z oparty o libarchive, gzip i 7z - + Author Autor - + aka. aka. - - + + About Arqiver O Arqiver - + Translators Tłumacze diff --git a/mainWin.cpp b/mainWin.cpp index 003c455..a66a294 100644 --- a/mainWin.cpp +++ b/mainWin.cpp @@ -44,7 +44,7 @@ mainWin::mainWin() : QMainWindow(), ui(new Ui::mainWin) { ui->setupUi(this); lastPath_ = QDir::homePath(); - updateTree_ = true; + updateTree_ = true; // will be set to false when extracting (or viewing) expandAll_ = false; close_ = false; processIsRunning_ = false; @@ -298,7 +298,7 @@ QHash mainWin::cleanTree(const QStringList& list) { const QString path = (*it)->whatsThis(0); if (!list.contains(path) || (*it)->data(2, Qt::UserRole).toString() != BACKEND->sizeString(path) // size change - /* also consider the possibility of lock state change*/ + /* also consider the possibility of lock state change */ || (BACKEND->is7z() && (((*it)->data(3, Qt::UserRole).toString() == "lock" // see updateTree() && !BACKEND->isEncryptedPath(path)) @@ -582,11 +582,34 @@ void mainWin::addDirs() { BACKEND->startAdd(QStringList() << dirs); } +// Check if this item or any of its children is encrypted. +bool mainWin::subTreeIsEncrypted(QTreeWidgetItem *item) { + if (BACKEND->isEncrypted() && BACKEND->getPswrd().isEmpty()) { + if (BACKEND->isEncryptedPath(item->whatsThis(0)) + && !BACKEND->is7zSingleExtracted(item->whatsThis(0))) { + return true; + } + int N = item->childCount(); + if (N > 0) { + for (int i = 0; i < N; ++i) { + if (subTreeIsEncrypted(item->child(i))) + return true; + } + } + } + return false; +} + void mainWin::removeFiles() { - QList sel = ui->tree_contents->selectedItems(); + const QList sel = ui->tree_contents->selectedItems(); QStringList items; - for (int i = 0; i < sel.length(); i++){ - items << sel[i]->whatsThis(0); + for (auto item : sel) { + if (subTreeIsEncrypted(item)) { + /* WARNING: It seems that 7z isn't self-consistent in removal of + encrypted files: sometimes it needs password, sometimes not. */ + if (!pswrdDialog()) return; + } + items << item->whatsThis(0); } items.removeDuplicates(); textLabel_->setText(tr("Removing Items...")); @@ -706,6 +729,7 @@ void mainWin::extractFiles() { QString dir = QFileDialog::getExistingDirectory(this, tr("Extract Into Directory"), lastPath_); if (dir.isEmpty()) return; lastPath_ = dir; + updateTree_ = false; textLabel_->setText(tr("Extracting...")); BACKEND->startExtract(dir); } @@ -716,6 +740,7 @@ void mainWin::autoextractFiles() { if (BACKEND->isEncrypted() && BACKEND->getPswrd().isEmpty()) { if (!pswrdDialog()) return; } + updateTree_ = false; textLabel_->setText(tr("Extracting...")); BACKEND->startExtract(dir); } @@ -776,7 +801,7 @@ void mainWin::extractSelection() { /* check overwriting with partial extractions */ if (!selList.isEmpty()) { selList.sort(); - for (auto &file : selList) { + for (const auto &file : qAsConst(selList)) { if (QFile::exists(dir + "/" + file.section("/",-1))) { QMessageBox::StandardButton btn = QMessageBox::question(this, tr("Question"), @@ -789,6 +814,7 @@ void mainWin::extractSelection() { } lastPath_ = dir; + updateTree_ = false; textLabel_->setText(tr("Extracting...")); BACKEND->startExtract(dir, selList); } @@ -863,7 +889,7 @@ void mainWin::updateTree() { QHash allPrevItems = cleanTree(files.size() > 10000 ? QStringList() : files); QHash dirs; // keep track of directory items - for (const QString& thisFile : static_cast(files)) { + for (const auto& thisFile : qAsConst(files)) { QTreeWidgetItem *item = allPrevItems.value(thisFile); if (item != nullptr) { // already in the tree widget if(BACKEND->isDir(thisFile)) @@ -873,12 +899,12 @@ void mainWin::updateTree() { QString mime; if (!BACKEND->isDir(thisFile)) - mime = BACKEND->getMimeType(thisFile.section("/",-1)); + mime = BACKEND->getMimeType(thisFile.section("/", -1)); QTreeWidgetItem *it = new QTreeWidgetItem(); /* set texts and icons */ QSize icnSize = ui->tree_contents->iconSize(); - it->setText(0, thisFile.section("/",-1)); + it->setText(0, thisFile.section("/", -1)); if (!mime.isEmpty()) { it->setText(3, "0"); // to put it after directory items if (!BACKEND->isLink(thisFile)) { @@ -926,7 +952,7 @@ void mainWin::updateTree() { sections.removeLast(); QTreeWidgetItem *parentItem = nullptr; QString theFile; - for (const QString& thisSection : static_cast(sections)) { + for (const auto& thisSection : qAsConst(sections)) { theFile += (theFile.isEmpty() ? QString() : "/") + thisSection; QTreeWidgetItem *thisParent = dirs.value(theFile); if (!thisParent) { diff --git a/mainWin.h b/mainWin.h index ba5193f..4d3e555 100644 --- a/mainWin.h +++ b/mainWin.h @@ -93,6 +93,7 @@ private slots: bool pswrdDialog(bool listEncryptionBox = false, bool forceListEncryption = false); QPixmap emblemize(const QString icon, const QSize& icnSize, bool lock); void enableActions(bool enable); + bool subTreeIsEncrypted(QTreeWidgetItem *item); QLabel *iconLabel_; Label *textLabel_;