diff options
Diffstat (limited to '')
-rw-r--r-- | heimdall-frontend/Source/Alerts.cpp | 2 | ||||
-rw-r--r-- | heimdall-frontend/Source/FirmwareInfo.cpp | 17 | ||||
-rw-r--r-- | heimdall-frontend/Source/FirmwareInfo.h | 2 | ||||
-rw-r--r-- | heimdall-frontend/Source/Packaging.cpp | 321 | ||||
-rw-r--r-- | heimdall-frontend/Source/Packaging.h | 5 |
5 files changed, 318 insertions, 29 deletions
diff --git a/heimdall-frontend/Source/Alerts.cpp b/heimdall-frontend/Source/Alerts.cpp index e8e8752..5dc0337 100644 --- a/heimdall-frontend/Source/Alerts.cpp +++ b/heimdall-frontend/Source/Alerts.cpp @@ -29,6 +29,7 @@ using namespace HeimdallFrontend; void Alerts::DisplayError(const QString& errorMessage) { QMessageBox messageBox; + messageBox.setModal(true); messageBox.setText(errorMessage); messageBox.setIcon(QMessageBox::Critical); messageBox.exec(); @@ -37,6 +38,7 @@ void Alerts::DisplayError(const QString& errorMessage) void Alerts::DisplayWarning(const QString& warningMessage) { QMessageBox messageBox; + messageBox.setModal(true); messageBox.setText(warningMessage); messageBox.setIcon(QMessageBox::Warning); messageBox.exec(); diff --git a/heimdall-frontend/Source/FirmwareInfo.cpp b/heimdall-frontend/Source/FirmwareInfo.cpp index aee9313..7870621 100644 --- a/heimdall-frontend/Source/FirmwareInfo.cpp +++ b/heimdall-frontend/Source/FirmwareInfo.cpp @@ -18,9 +18,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ +// Qt +#include "QRegExp" + // Heimdall Frontend #include "Alerts.h" #include "FirmwareInfo.h" +#include "Packaging.h" using namespace HeimdallFrontend; @@ -320,7 +324,7 @@ bool FileInfo::ParseXml(QXmlStreamReader& xml) return (false); } -void FileInfo::WriteXml(QXmlStreamWriter& xml) const +void FileInfo::WriteXml(QXmlStreamWriter& xml, const QString& filename) const { xml.writeStartElement("file"); @@ -329,14 +333,7 @@ void FileInfo::WriteXml(QXmlStreamWriter& xml) const xml.writeEndElement(); xml.writeStartElement("filename"); - - int lastSlash = filename.lastIndexOf('/'); - - if (lastSlash < 0) - lastSlash = filename.lastIndexOf('\\'); - - xml.writeCharacters(filename.mid(lastSlash + 1)); - + xml.writeCharacters(filename); xml.writeEndElement(); xml.writeEndElement(); @@ -775,7 +772,7 @@ void FirmwareInfo::WriteXml(QXmlStreamWriter& xml) const xml.writeStartElement("files"); for (int i = 0; i < fileInfos.length(); i++) - fileInfos[i].WriteXml(xml); + fileInfos[i].WriteXml(xml, Packaging::ClashlessFilename(fileInfos, i)); xml.writeEndElement(); diff --git a/heimdall-frontend/Source/FirmwareInfo.h b/heimdall-frontend/Source/FirmwareInfo.h index 64c73cb..5765199 100644 --- a/heimdall-frontend/Source/FirmwareInfo.h +++ b/heimdall-frontend/Source/FirmwareInfo.h @@ -126,7 +126,7 @@ namespace HeimdallFrontend FileInfo(unsigned int partitionId, const QString& filename); bool ParseXml(QXmlStreamReader& xml); - void WriteXml(QXmlStreamWriter& xml) const; + void WriteXml(QXmlStreamWriter& xml, const QString& filename) const; unsigned int GetPartitionId(void) const { diff --git a/heimdall-frontend/Source/Packaging.cpp b/heimdall-frontend/Source/Packaging.cpp index fc41ba6..6c3890b 100644 --- a/heimdall-frontend/Source/Packaging.cpp +++ b/heimdall-frontend/Source/Packaging.cpp @@ -221,12 +221,12 @@ bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData) return (true); } -bool Packaging::WriteTarEntry(const QString& filename, QTemporaryFile *tarFile, bool firmwareXml) +bool Packaging::WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename) { TarHeader tarHeader; memset(tarHeader.buffer, 0, TarHeader::kBlockLength); - QFile file(filename); + QFile file(filePath); if (!file.open(QFile::ReadOnly)) { @@ -243,19 +243,12 @@ bool Packaging::WriteTarEntry(const QString& filename, QTemporaryFile *tarFile, QFileInfo qtFileInfo(file); QByteArray utfFilename; - if (firmwareXml) - { - utfFilename = QString("firmware.xml").toUtf8(); - } - else - { - utfFilename = qtFileInfo.fileName().toUtf8(); + utfFilename = entryFilename.toUtf8(); - if (utfFilename.length() > 100) - { - Alerts::DisplayError(QString("File name is too long:\n%1").arg(qtFileInfo.fileName())); - return (false); - } + if (utfFilename.length() > 100) + { + Alerts::DisplayError(QString("File name is too long:\n%1").arg(qtFileInfo.fileName())); + return (false); } strcpy(tarHeader.fields.name, utfFilename.constData()); @@ -388,7 +381,15 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF for (int i = 0; i < fileInfos.length(); i++) { - if (!WriteTarEntry(fileInfos[i].GetFilename(), tarFile)) + QString filename = ClashlessFilename(fileInfos, i); + + if (filename == "firmware.xml") + { + Alerts::DisplayError("You cannot name your partition files \"firmware.xml\".\nIt is a reserved name."); + return (false); + } + + if (!WriteTarEntry(fileInfos[i].GetFilename(), tarFile, ClashlessFilename(fileInfos, i))) { tarFile->resize(0); tarFile->close(); @@ -411,7 +412,20 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF } } - if (!WriteTarEntry(firmwareInfo.GetPitFilename(), tarFile)) + int lastSlash = firmwareInfo.GetPitFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = firmwareInfo.GetPitFilename().lastIndexOf('\\'); + + QString pitFilename = ClashlessFilename(fileInfos, firmwareInfo.GetPitFilename().mid(lastSlash + 1)); + + if (pitFilename == "firmware.xml") + { + Alerts::DisplayError("You cannot name your PIT file \"firmware.xml\".\nIt is a reserved name."); + return (false); + } + + if (!WriteTarEntry(firmwareInfo.GetPitFilename(), tarFile, pitFilename)) { tarFile->resize(0); tarFile->close(); @@ -431,7 +445,7 @@ bool Packaging::CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarF return (false); } - if (!WriteTarEntry(firmwareXmlFile.fileName(), tarFile, true)) + if (!WriteTarEntry(firmwareXmlFile.fileName(), tarFile, "firmware.xml")) { tarFile->resize(0); tarFile->close(); @@ -558,7 +572,12 @@ bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& fir QTemporaryFile tar("XXXXXX.tar"); if (!CreateTar(firmwareInfo, &tar)) + { + fclose(compressedPackageFile); + remove(packagePath.toStdString().c_str()); + return (false); + } if (!tar.open()) { @@ -626,3 +645,271 @@ bool Packaging::BuildPackage(const QString& packagePath, const FirmwareInfo& fir return (true); } + +QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, int fileInfoIndex) +{ + int lastSlash = fileInfos[fileInfoIndex].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[fileInfoIndex].GetFilename().lastIndexOf('\\'); + + QString filename = fileInfos[fileInfoIndex].GetFilename().mid(lastSlash + 1); + unsigned int renameIndex = 0; + + // Check for name clashes + for (int i = 0; i < fileInfoIndex; i++) + { + lastSlash = fileInfos[i].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\'); + + QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1); + + if (filename == otherFilename) + renameIndex++; + } + + if (renameIndex > 0) + { + int lastPeriodIndex = filename.lastIndexOf(QChar('.')); + QString shortFilename; + QString fileType; + + if (lastPeriodIndex >= 0) + { + shortFilename = filename.left(lastPeriodIndex); + fileType = filename.mid(lastPeriodIndex); + } + else + { + shortFilename = filename; + } + + unsigned int renameIndexOffset = 0; + bool validIndexOffset = true; + + // Before we append a rename index we must ensure it doesn't produce further collisions. + for (int i = 0; i < fileInfos.length(); i++) + { + int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\'); + + QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1); + + if (otherFilename.length() > filename.length() + 1) + { + QString trimmedOtherFilename = otherFilename.left(shortFilename.length()); + + if (shortFilename == trimmedOtherFilename) + { + lastPeriodIndex = otherFilename.lastIndexOf(QChar('.')); + QString shortOtherFilename; + + if (lastPeriodIndex >= 0) + shortOtherFilename = otherFilename.left(lastPeriodIndex); + else + shortOtherFilename = otherFilename; + + QRegExp renameExp("-[0-9]+"); + + if (renameExp.lastIndexIn(shortOtherFilename) == shortFilename.length()) + { + unsigned int trailingInteger = shortOtherFilename.mid(shortFilename.length() + 1).toUInt(&validIndexOffset); + + if (!validIndexOffset) + break; + + if (trailingInteger > renameIndexOffset) + renameIndexOffset = trailingInteger; + } + } + } + } + + if (validIndexOffset) + { + // Ensure renaming won't involve integer overflow! + if (renameIndex > static_cast<unsigned int>(-1) - renameIndexOffset) + validIndexOffset = false; + } + + if (validIndexOffset) + { + shortFilename.append(QChar('-')); + shortFilename.append(QString::number(renameIndexOffset + renameIndex)); + + return (shortFilename + fileType); + } + else + { + // Fallback behaviour... an absolutely terrible brute force implementation! + QString filename; + QString renamePrefix; + + for (;;) + { + renamePrefix.append(QChar('+')); + + for (unsigned int i = 0; i < static_cast<unsigned int>(-1); i++) + { + filename = shortFilename + renamePrefix + QString::number(i) + fileType; + + bool valid = true; + + for (int i = 0; i < fileInfos.length(); i++) + { + int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\'); + + if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1)) + { + valid = false; + break; + } + } + + if (valid) + return (filename); + } + } + } + } + else + { + return (filename); + } +} + +QString Packaging::ClashlessFilename(const QList<FileInfo>& fileInfos, const QString& filename) +{ + unsigned int renameIndex = 0; + + // Check for name clashes + for (int i = 0; i < fileInfos.length(); i++) + { + int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\'); + + QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1); + + if (filename == otherFilename) + renameIndex++; + } + + if (renameIndex > 0) + { + int lastPeriodIndex = filename.lastIndexOf(QChar('.')); + QString shortFilename; + QString fileType; + + if (lastPeriodIndex >= 0) + { + shortFilename = filename.left(lastPeriodIndex); + fileType = filename.mid(lastPeriodIndex); + } + else + { + shortFilename = filename; + } + + unsigned int renameIndexOffset = 0; + bool validIndexOffset = true; + + // Before we append a rename index we must ensure it doesn't produce further collisions. + for (int i = 0; i < fileInfos.length(); i++) + { + int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\'); + + QString otherFilename = fileInfos[i].GetFilename().mid(lastSlash + 1); + + if (otherFilename.length() > filename.length() + 1) + { + QString trimmedOtherFilename = otherFilename.left(filename.length()); + + if (filename == trimmedOtherFilename) + { + lastPeriodIndex = otherFilename.lastIndexOf(QChar('.')); + QString shortOtherFilename; + + if (lastPeriodIndex >= 0) + shortOtherFilename = otherFilename.left(lastPeriodIndex); + else + shortOtherFilename = otherFilename; + + QRegExp renameExp("-[0-9]+"); + + if (renameExp.lastIndexIn(shortOtherFilename) == shortFilename.length()) + { + unsigned int trailingInteger = shortOtherFilename.mid(shortFilename.length() + 1).toUInt(&validIndexOffset); + + if (!validIndexOffset) + break; + + if (trailingInteger > renameIndexOffset) + renameIndexOffset = trailingInteger; + } + } + } + } + + if (validIndexOffset) + { + // Ensure renaming won't involve integer overflow! + if (renameIndex > static_cast<unsigned int>(-1) - renameIndexOffset) + validIndexOffset = false; + } + + if (validIndexOffset) + { + shortFilename.append(QChar('-')); + shortFilename.append(QString::number(renameIndexOffset + renameIndex)); + + return (shortFilename + fileType); + } + else + { + // Fallback behaviour, brute-force/semi-random. + bool valid; + QString filename; + + do + { + valid = true; + + filename = shortFilename + "-"; + for (int i = 0; i < 8; i++) + filename.append(QChar(qrand() % ('Z' - 'A' + 1) + 'A')); + + for (int i = 0; i < fileInfos.length(); i++) + { + int lastSlash = fileInfos[i].GetFilename().lastIndexOf('/'); + + if (lastSlash < 0) + lastSlash = fileInfos[i].GetFilename().lastIndexOf('\\'); + + if (filename == fileInfos[i].GetFilename().mid(lastSlash + 1)) + { + valid = false; + break; + } + } + } while (!valid); + + return (filename); + } + } + else + { + return (filename); + } +} diff --git a/heimdall-frontend/Source/Packaging.h b/heimdall-frontend/Source/Packaging.h index 402f786..b6bac8d 100644 --- a/heimdall-frontend/Source/Packaging.h +++ b/heimdall-frontend/Source/Packaging.h @@ -103,7 +103,7 @@ namespace HeimdallFrontend // TODO: Add support for sparse files to both methods? static bool ExtractTar(QTemporaryFile& tarFile, PackageData *packageData); - static bool WriteTarEntry(const QString& filename, QTemporaryFile *tarFile, bool firmwareXml = false); + static bool WriteTarEntry(const QString& filePath, QTemporaryFile *tarFile, const QString& entryFilename); static bool CreateTar(const FirmwareInfo& firmwareInfo, QTemporaryFile *tarFile); // Uses original TAR format. public: @@ -112,6 +112,9 @@ namespace HeimdallFrontend static bool ExtractPackage(const QString& packagePath, PackageData *packageData); static bool BuildPackage(const QString& packagePath, const FirmwareInfo& firmwareInfo); + + static QString ClashlessFilename(const QList<FileInfo>& fileInfos, int fileInfoIndex); + static QString ClashlessFilename(const QList<FileInfo>& fileInfos, const QString& filename); }; } |