diff options
author | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2022-04-13 17:28:11 +0300 |
---|---|---|
committer | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2022-04-21 14:24:31 +0000 |
commit | e3eef62c1bb7731c8cea64579c39739bd7b27b70 (patch) | |
tree | 7738b8c79b79d011feffc940bb4e956451c0035a | |
parent | 99db65c70ab7cdc458e197440af8251cd48c8e89 (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.h | 24 |
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: |