summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-04-13 17:28:11 +0300
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-04-21 14:24:31 +0000
commite3eef62c1bb7731c8cea64579c39739bd7b27b70 (patch)
tree7738b8c79b79d011feffc940bb4e956451c0035a
parent99db65c70ab7cdc458e197440af8251cd48c8e89 (diff)
Fix rollback of extract when archive lists file entries first
At least with the 7z format packaged with a recent archivegen version, the directory entries from archives get processed last when extracting. We remember the path of each extracted entry in the order the writing happens, to be able to undo the extract later. The directories need to be empty for the removing to succeed, so we cannot rely that the entry order from extraction is correct. Ensure files are removed before directories and that the directories are removed in an order starting from the deepest subdirectory level. Task-number: QTIFW-2594 Change-Id: I8a914c4bf69147b845b12f0481c49c93408b51fd Reviewed-by: Katja Marttila <katja.marttila@qt.io>
-rw-r--r--src/libs/installer/extractarchiveoperation_p.h24
1 files changed, 22 insertions, 2 deletions
diff --git a/src/libs/installer/extractarchiveoperation_p.h b/src/libs/installer/extractarchiveoperation_p.h
index f440af23b..04b152259 100644
--- a/src/libs/installer/extractarchiveoperation_p.h
+++ b/src/libs/installer/extractarchiveoperation_p.h
@@ -63,6 +63,8 @@ public:
{
Q_ASSERT(m_op != 0);
+ QStringList directories;
+
int removedCounter = 0;
foreach (const QString &file, m_files) {
removedCounter++;
@@ -73,10 +75,28 @@ public:
if (fi.isFile() || fi.isSymLink()) {
m_op->deleteFileNowOrLater(fi.absoluteFilePath());
} else if (fi.isDir()) {
- removeSystemGeneratedFiles(file);
- fi.dir().rmdir(file); // directory may not exist
+ directories.append(file);
}
}
+
+ std::sort(directories.begin(), directories.end(), [](const QString &lhs, const QString &rhs) {
+ // Doesn't match the original creation order, nor will the sorted list be a logical
+ // directory tree. Only requirement is that subdirectories get removed first.
+ const int lhsParts = QDir::fromNativeSeparators(lhs)
+ .split(QLatin1Char('/'), Qt::SkipEmptyParts).size();
+ const int rhsParts = QDir::fromNativeSeparators(rhs)
+ .split(QLatin1Char('/'), Qt::SkipEmptyParts).size();
+
+ if (lhsParts == rhsParts)
+ return lhs < rhs;
+
+ return lhsParts > rhsParts;
+ });
+
+ for (auto &directory : qAsConst(directories)) {
+ removeSystemGeneratedFiles(directory);
+ QDir(directory).rmdir(directory); // directory may not exist
+ }
}
signals: