Warning, file /frameworks/karchive/autotests/karchivetest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 SPDX-FileCopyrightText: 2006, 2010 David Faure <faure@kde.org> 0003 SPDX-FileCopyrightText: 2012 Mario Bensi <mbensi@ipsquad.net> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "karchivetest.h" 0009 #include <k7zip.h> 0010 #include <kar.h> 0011 #include <krcc.h> 0012 #include <ktar.h> 0013 #include <kzip.h> 0014 0015 #include <QDebug> 0016 #include <QTest> 0017 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0018 #include <QTextCodec> 0019 #endif 0020 #include <QFileInfo> 0021 #include <QRegularExpression> 0022 #include <QSaveFile> 0023 #include <QStandardPaths> 0024 #include <QTemporaryDir> 0025 #include <kcompressiondevice.h> 0026 0027 #ifndef Q_OS_WIN 0028 #include <cerrno> 0029 #include <unistd.h> // symlink 0030 #endif 0031 0032 #ifdef Q_OS_WIN 0033 #include <QScopedValueRollback> 0034 #include <Windows.h> 0035 #else 0036 #include <grp.h> 0037 #include <pwd.h> 0038 #endif 0039 0040 QTEST_MAIN(KArchiveTest) 0041 0042 void initLocale() 0043 { 0044 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0045 // KArchive uses QFile::decodeName, and our tests use utf8 encoding for filenames 0046 QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8")); 0047 #endif 0048 } 0049 Q_CONSTRUCTOR_FUNCTION(initLocale) 0050 0051 static const int SIZE1 = 100; 0052 0053 /** 0054 * Writes test fileset specified archive 0055 * @param archive archive 0056 */ 0057 static void writeTestFilesToArchive(KArchive *archive) 0058 { 0059 QVERIFY(archive->writeFile("empty", "", 0100644, "weis", "users")); 0060 QVERIFY(archive->writeFile("test1", QByteArray("Hallo"), 0100440, QString("weis"), QString("users"))); 0061 // Now let's try with the prepareWriting/writeData/finishWriting API 0062 QVERIFY(archive->prepareWriting("test2", "weis", "users", 8)); 0063 QVERIFY(archive->writeData("Hallo ", 6)); 0064 QVERIFY(archive->writeData("Du", 2)); 0065 QVERIFY(archive->finishWriting(8)); 0066 // Add local file 0067 QFile localFile(QStringLiteral("test3")); 0068 QVERIFY(localFile.open(QIODevice::WriteOnly)); 0069 QVERIFY(localFile.write("Noch so einer", 13) == 13); 0070 localFile.close(); 0071 0072 QVERIFY(archive->addLocalFile("test3", "z/test3")); 0073 0074 // writeFile API 0075 QVERIFY(archive->writeFile("my/dir/test3", "I do not speak German\nDavid.", 0100644, "dfaure", "hackers")); 0076 0077 // Now a medium file : 100 null bytes 0078 char medium[SIZE1] = {0}; 0079 QVERIFY(archive->writeFile("mediumfile", QByteArray(medium, SIZE1))); 0080 // Another one, with an absolute path 0081 QVERIFY(archive->writeFile("/dir/subdir/mediumfile2", QByteArray(medium, SIZE1))); 0082 0083 // Now a huge file : 20000 null bytes 0084 int n = 20000; 0085 char *huge = new char[n]; 0086 memset(huge, 0, n); 0087 QVERIFY(archive->writeFile("hugefile", QByteArray(huge, n))); 0088 delete[] huge; 0089 0090 // Now an empty directory 0091 QVERIFY(archive->writeDir("aaaemptydir")); 0092 0093 #ifndef Q_OS_WIN 0094 // Add local symlink 0095 QVERIFY(archive->addLocalFile("test3_symlink", "z/test3_symlink")); 0096 #endif 0097 0098 // Add executable 0099 QVERIFY(archive->writeFile("executableAll", "#!/bin/sh\necho hi", 0100755)); 0100 } 0101 0102 static QString getCurrentUserName() 0103 { 0104 #if defined(Q_OS_UNIX) 0105 struct passwd *pw = getpwuid(getuid()); 0106 return pw ? QFile::decodeName(pw->pw_name) : QString::number(getuid()); 0107 #elif defined(Q_OS_WIN) 0108 wchar_t buffer[255]; 0109 DWORD size = 255; 0110 bool ok = GetUserNameW(buffer, &size); 0111 if (!ok) { 0112 return QString(); 0113 } 0114 return QString::fromWCharArray(buffer); 0115 #else 0116 return QString(); 0117 #endif 0118 } 0119 0120 static QString getCurrentGroupName() 0121 { 0122 #if defined(Q_OS_UNIX) 0123 struct group *grp = getgrgid(getgid()); 0124 return grp ? QFile::decodeName(grp->gr_name) : QString::number(getgid()); 0125 #elif defined(Q_OS_WIN) 0126 return QString(); 0127 #else 0128 return QString(); 0129 #endif 0130 } 0131 0132 enum ListingFlags { 0133 WithUserGroup = 1, 0134 WithTime = 0x02, 0135 }; // ListingFlags 0136 0137 static QStringList recursiveListEntries(const KArchiveDirectory *dir, const QString &path, int listingFlags) 0138 { 0139 QStringList ret; 0140 QStringList l = dir->entries(); 0141 l.sort(); 0142 for (const QString &it : std::as_const(l)) { 0143 const KArchiveEntry *entry = dir->entry(it); 0144 0145 QString descr; 0146 descr += QStringLiteral("mode=") + QString::number(entry->permissions(), 8) + ' '; 0147 if (listingFlags & WithUserGroup) { 0148 descr += QStringLiteral("user=") + entry->user() + ' '; 0149 descr += QStringLiteral("group=") + entry->group() + ' '; 0150 } 0151 descr += QStringLiteral("path=") + path + (it) + ' '; 0152 descr += QStringLiteral("type=") + (entry->isDirectory() ? "dir" : "file"); 0153 if (entry->isFile()) { 0154 descr += QStringLiteral(" size=") + QString::number(static_cast<const KArchiveFile *>(entry)->size()); 0155 } 0156 if (!entry->symLinkTarget().isEmpty()) { 0157 descr += QStringLiteral(" symlink=") + entry->symLinkTarget(); 0158 } 0159 0160 if (listingFlags & WithTime) { 0161 descr += QStringLiteral(" time=") + entry->date().toString(QStringLiteral("dd.MM.yyyy hh:mm:ss")); 0162 } 0163 0164 // qDebug() << descr; 0165 ret.append(descr); 0166 0167 if (entry->isDirectory()) { 0168 ret += recursiveListEntries((KArchiveDirectory *)entry, path + it + '/', listingFlags); 0169 } 0170 } 0171 return ret; 0172 } 0173 0174 /** 0175 * Verifies contents of specified archive against test fileset 0176 * @param archive archive 0177 */ 0178 static void testFileData(KArchive *archive) 0179 { 0180 const KArchiveDirectory *dir = archive->directory(); 0181 0182 const KArchiveFile *f = dir->file(QStringLiteral("z/test3")); 0183 QVERIFY(f); 0184 0185 QByteArray arr(f->data()); 0186 QCOMPARE(arr.size(), 13); 0187 QCOMPARE(arr, QByteArray("Noch so einer")); 0188 0189 // Now test using createDevice() 0190 QIODevice *dev = f->createDevice(); 0191 QByteArray contents = dev->readAll(); 0192 QCOMPARE(contents, arr); 0193 delete dev; 0194 0195 dev = f->createDevice(); 0196 contents = dev->read(5); // test reading in two chunks 0197 QCOMPARE(contents.size(), 5); 0198 contents += dev->read(50); 0199 QCOMPARE(contents.size(), 13); 0200 QCOMPARE(QString::fromLatin1(contents.constData()), QString::fromLatin1(arr.constData())); 0201 delete dev; 0202 0203 // test read/seek/peek work fine 0204 f = dir->file(QStringLiteral("test1")); 0205 dev = f->createDevice(); 0206 contents = dev->peek(4); 0207 QCOMPARE(contents, QByteArray("Hall")); 0208 contents = dev->peek(2); 0209 QCOMPARE(contents, QByteArray("Ha")); 0210 dev->seek(2); 0211 contents = dev->peek(2); 0212 QCOMPARE(contents, QByteArray("ll")); 0213 dev->seek(0); 0214 contents = dev->read(2); 0215 QCOMPARE(contents, QByteArray("Ha")); 0216 contents = dev->peek(2); 0217 QCOMPARE(contents, QByteArray("ll")); 0218 dev->seek(1); 0219 contents = dev->read(1); 0220 QCOMPARE(contents, QByteArray("a")); 0221 dev->seek(4); 0222 contents = dev->read(1); 0223 QCOMPARE(contents, QByteArray("o")); 0224 delete dev; 0225 0226 const KArchiveEntry *e = dir->entry(QStringLiteral("mediumfile")); 0227 QVERIFY(e && e->isFile()); 0228 f = (KArchiveFile *)e; 0229 QCOMPARE(f->data().size(), SIZE1); 0230 0231 f = dir->file(QStringLiteral("hugefile")); 0232 QCOMPARE(f->data().size(), 20000); 0233 0234 e = dir->entry(QStringLiteral("aaaemptydir")); 0235 QVERIFY(e && e->isDirectory()); 0236 QVERIFY(!dir->file("aaaemptydir")); 0237 0238 e = dir->entry(QStringLiteral("my/dir/test3")); 0239 QVERIFY(e && e->isFile()); 0240 f = (KArchiveFile *)e; 0241 dev = f->createDevice(); 0242 QByteArray firstLine = dev->readLine(); 0243 QCOMPARE(QString::fromLatin1(firstLine.constData()), QString::fromLatin1("I do not speak German\n")); 0244 QByteArray secondLine = dev->read(100); 0245 QCOMPARE(QString::fromLatin1(secondLine.constData()), QString::fromLatin1("David.")); 0246 delete dev; 0247 #ifndef Q_OS_WIN 0248 e = dir->entry(QStringLiteral("z/test3_symlink")); 0249 QVERIFY(e); 0250 QVERIFY(e->isFile()); 0251 QCOMPARE(e->symLinkTarget(), QString("test3")); 0252 #endif 0253 0254 // Test "./" prefix for KOffice (xlink:href="./ObjectReplacements/Object 1") 0255 e = dir->entry(QStringLiteral("./hugefile")); 0256 QVERIFY(e && e->isFile()); 0257 e = dir->entry(QStringLiteral("./my/dir/test3")); 0258 QVERIFY(e && e->isFile()); 0259 0260 // Test directory entries 0261 e = dir->entry(QStringLiteral("my")); 0262 QVERIFY(e && e->isDirectory()); 0263 e = dir->entry(QStringLiteral("my/")); 0264 QVERIFY(e && e->isDirectory()); 0265 e = dir->entry(QStringLiteral("./my/")); 0266 QVERIFY(e && e->isDirectory()); 0267 } 0268 0269 static void testReadWrite(KArchive *archive) 0270 { 0271 QVERIFY(archive->writeFile("newfile", "New File", 0100440, "dfaure", "users")); 0272 } 0273 0274 #ifdef Q_OS_WIN 0275 extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; 0276 #endif 0277 0278 static void testCopyTo(KArchive *archive) 0279 { 0280 const KArchiveDirectory *dir = archive->directory(); 0281 QTemporaryDir tmpDir; 0282 const QString dirName = tmpDir.path() + '/'; 0283 0284 QVERIFY(dir->copyTo(dirName)); 0285 0286 QVERIFY(QFile::exists(dirName + "dir")); 0287 QVERIFY(QFileInfo(dirName + "dir").isDir()); 0288 0289 QFileInfo fileInfo1(dirName + "dir/subdir/mediumfile2"); 0290 QVERIFY(fileInfo1.exists()); 0291 QVERIFY(fileInfo1.isFile()); 0292 QCOMPARE(fileInfo1.size(), Q_INT64_C(100)); 0293 0294 QFileInfo fileInfo2(dirName + "hugefile"); 0295 QVERIFY(fileInfo2.exists()); 0296 QVERIFY(fileInfo2.isFile()); 0297 QCOMPARE(fileInfo2.size(), Q_INT64_C(20000)); 0298 0299 QFileInfo fileInfo3(dirName + "mediumfile"); 0300 QVERIFY(fileInfo3.exists()); 0301 QVERIFY(fileInfo3.isFile()); 0302 QCOMPARE(fileInfo3.size(), Q_INT64_C(100)); 0303 0304 QFileInfo fileInfo4(dirName + "my/dir/test3"); 0305 QVERIFY(fileInfo4.exists()); 0306 QVERIFY(fileInfo4.isFile()); 0307 QCOMPARE(fileInfo4.size(), Q_INT64_C(28)); 0308 0309 #ifndef Q_OS_WIN 0310 const QString fileName = dirName + "z/test3_symlink"; 0311 const QFileInfo fileInfo5(fileName); 0312 QVERIFY(fileInfo5.exists()); 0313 QVERIFY(fileInfo5.isFile()); 0314 // Do not use fileInfo.symLinkTarget() for unix symlinks 0315 // It returns the -full- path to the target, while we want the target string "as is". 0316 QString symLinkTarget; 0317 const QByteArray encodedFileName = QFile::encodeName(fileName); 0318 QByteArray s; 0319 #if defined(PATH_MAX) 0320 s.resize(PATH_MAX + 1); 0321 #else 0322 int path_max = pathconf(encodedFileName.data(), _PC_PATH_MAX); 0323 if (path_max <= 0) { 0324 path_max = 4096; 0325 } 0326 s.resize(path_max); 0327 #endif 0328 int len = readlink(encodedFileName.data(), s.data(), s.size() - 1); 0329 if (len >= 0) { 0330 s[len] = '\0'; 0331 symLinkTarget = QFile::decodeName(s.constData()); 0332 } 0333 QCOMPARE(symLinkTarget, QString("test3")); 0334 #endif 0335 0336 #ifdef Q_OS_WIN 0337 QScopedValueRollback<int> ntfsMode(qt_ntfs_permission_lookup); 0338 qt_ntfs_permission_lookup++; 0339 #endif 0340 QVERIFY(QFileInfo(dirName + "executableAll").permissions() & (QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther)); 0341 } 0342 0343 /** 0344 * Prepares dataset for archive filter tests 0345 */ 0346 void KArchiveTest::setupData() 0347 { 0348 QTest::addColumn<QString>("fileName"); 0349 QTest::addColumn<QString>("mimeType"); 0350 0351 QTest::newRow(".tar.gz") << "karchivetest.tar.gz" 0352 << "application/gzip"; 0353 #if HAVE_BZIP2_SUPPORT 0354 QTest::newRow(".tar.bz2") << "karchivetest.tar.bz2" 0355 << "application/x-bzip"; 0356 #endif 0357 #if HAVE_XZ_SUPPORT 0358 QTest::newRow(".tar.lzma") << "karchivetest.tar.lzma" 0359 << "application/x-lzma"; 0360 QTest::newRow(".tar.xz") << "karchivetest.tar.xz" 0361 << "application/x-xz"; 0362 #endif 0363 #if HAVE_ZSTD_SUPPORT 0364 QTest::newRow(".tar.zst") << "karchivetest.tar.zst" 0365 << "application/zstd"; 0366 #endif 0367 } 0368 0369 /** 0370 * @see QTest::initTestCase() 0371 */ 0372 void KArchiveTest::initTestCase() 0373 { 0374 #ifndef Q_OS_WIN 0375 // Prepare local symlink 0376 QFile::remove(QStringLiteral("test3_symlink")); 0377 if (::symlink("test3", "test3_symlink") != 0) { 0378 qDebug() << errno; 0379 QVERIFY(false); 0380 } 0381 #endif 0382 // avoid interference from kdebugsettings on qCWarning 0383 QStandardPaths::setTestModeEnabled(true); 0384 } 0385 0386 void KArchiveTest::testEmptyFilename() 0387 { 0388 QTest::ignoreMessage(QtWarningMsg, "KArchive: No file name specified"); 0389 KTar tar(QLatin1String("")); 0390 QVERIFY(!tar.open(QIODevice::ReadOnly)); 0391 QCOMPARE(tar.errorString(), tr("No filename or device was specified")); 0392 } 0393 0394 void KArchiveTest::testNullDevice() 0395 { 0396 QIODevice *nil = nullptr; 0397 QTest::ignoreMessage(QtWarningMsg, "KArchive: Null device specified"); 0398 KTar tar(nil); 0399 QVERIFY(!tar.open(QIODevice::ReadOnly)); 0400 QCOMPARE(tar.errorString(), tr("No filename or device was specified")); 0401 } 0402 0403 void KArchiveTest::testNonExistentFile() 0404 { 0405 KTar tar(QStringLiteral("nonexistent.tar.gz")); 0406 QVERIFY(!tar.open(QIODevice::ReadOnly)); 0407 QCOMPARE(tar.errorString(), tr("File %1 does not exist").arg("nonexistent.tar.gz")); 0408 } 0409 0410 void KArchiveTest::testCreateTar_data() 0411 { 0412 QTest::addColumn<QString>("fileName"); 0413 QTest::newRow(".tar") << "karchivetest.tar"; 0414 } 0415 0416 /** 0417 * @dataProvider testCreateTar_data 0418 */ 0419 void KArchiveTest::testCreateTar() 0420 { 0421 QFETCH(QString, fileName); 0422 0423 // With tempfile: 0.7-0.8 ms, 994236 instr. loads 0424 // Without tempfile: 0.81 ms, 992541 instr. loads 0425 // Note: use ./karchivetest 2>&1 | grep ms 0426 // to avoid being slowed down by the kDebugs. 0427 QBENCHMARK { 0428 KTar tar(fileName); 0429 QVERIFY(tar.open(QIODevice::WriteOnly)); 0430 0431 writeTestFilesToArchive(&tar); 0432 0433 QVERIFY(tar.close()); 0434 0435 QFileInfo fileInfo(QFile::encodeName(fileName)); 0436 QVERIFY(fileInfo.exists()); 0437 // We can't check for an exact size because of the addLocalFile, whose data is system-dependent 0438 QVERIFY(fileInfo.size() > 450); 0439 } 0440 0441 // NOTE The only .tar test, cleanup here 0442 // QFile::remove(fileName); 0443 } 0444 0445 /** 0446 * @dataProvider setupData 0447 */ 0448 void KArchiveTest::testCreateTarXXX() 0449 { 0450 QFETCH(QString, fileName); 0451 0452 // With tempfile: 1.3-1.7 ms, 2555089 instr. loads 0453 // Without tempfile: 0.87 ms, 987915 instr. loads 0454 QBENCHMARK { 0455 KTar tar(fileName); 0456 QVERIFY(tar.open(QIODevice::WriteOnly)); 0457 0458 writeTestFilesToArchive(&tar); 0459 0460 QVERIFY(tar.close()); 0461 0462 QFileInfo fileInfo(QFile::encodeName(fileName)); 0463 QVERIFY(fileInfo.exists()); 0464 // We can't check for an exact size because of the addLocalFile, whose data is system-dependent 0465 QVERIFY(fileInfo.size() > 350); 0466 } 0467 } 0468 0469 // static void compareEntryWithTimestamp(const QString &dateString, const QString &expectedDateString, const QDateTime &expectedDateTime) 0470 // Made it a macro so that line numbers are meaningful on failure 0471 0472 #define compareEntryWithTimestamp(dateString, expectedDateString, expectedDateTime) \ 0473 { \ 0474 /* Take the time from the listing and chop it off */ \ 0475 const QDateTime dt = QDateTime::fromString(dateString.right(19), "dd.MM.yyyy hh:mm:ss"); \ 0476 QString _str(dateString); \ 0477 _str.chop(25); \ 0478 QCOMPARE(_str, expectedDateString); \ 0479 \ 0480 /* Compare the times separately with allowed 2 sec diversion */ \ 0481 if (dt.secsTo(expectedDateTime) > 2) { \ 0482 qWarning() << dt << "is too different from" << expectedDateTime; \ 0483 } \ 0484 QVERIFY(dt.secsTo(expectedDateTime) <= 2); \ 0485 } 0486 0487 /** 0488 * @dataProvider setupData 0489 */ 0490 void KArchiveTest::testReadTar() // testCreateTarGz must have been run first. 0491 { 0492 QFETCH(QString, fileName); 0493 0494 QFileInfo localFileData(QStringLiteral("test3")); 0495 0496 const QString systemUserName = getCurrentUserName(); 0497 const QString systemGroupName = getCurrentGroupName(); 0498 const QString owner = localFileData.owner(); 0499 const QString group = localFileData.group(); 0500 const QString emptyTime = QDateTime().toString(QStringLiteral("dd.MM.yyyy hh:mm:ss")); 0501 const QDateTime creationTime = QFileInfo(fileName).birthTime(); 0502 0503 // 1.6-1.7 ms per interaction, 2908428 instruction loads 0504 // After the "no tempfile when writing fix" this went down 0505 // to 0.9-1.0 ms, 1689059 instruction loads. 0506 // I guess it finds the data in the kernel cache now that no KTempFile is 0507 // used when writing. 0508 QBENCHMARK { 0509 KTar tar(fileName); 0510 0511 QVERIFY(tar.open(QIODevice::ReadOnly)); 0512 0513 const KArchiveDirectory *dir = tar.directory(); 0514 QVERIFY(dir != nullptr); 0515 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup | WithTime); 0516 0517 #ifndef Q_OS_WIN 0518 const int expectedCount = 16; 0519 #else 0520 const int expectedCount = 15; 0521 #endif 0522 if (listing.count() != expectedCount) { 0523 qWarning() << listing; 0524 } 0525 QCOMPARE(listing.count(), expectedCount); 0526 compareEntryWithTimestamp(listing[0], QString("mode=40755 user= group= path=aaaemptydir type=dir"), creationTime); 0527 0528 QCOMPARE(listing[1], QString("mode=40777 user=%1 group=%2 path=dir type=dir time=%3").arg(systemUserName).arg(systemGroupName).arg(emptyTime)); 0529 QCOMPARE(listing[2], QString("mode=40777 user=%1 group=%2 path=dir/subdir type=dir time=%3").arg(systemUserName).arg(systemGroupName).arg(emptyTime)); 0530 compareEntryWithTimestamp(listing[3], QString("mode=100644 user= group= path=dir/subdir/mediumfile2 type=file size=100"), creationTime); 0531 compareEntryWithTimestamp(listing[4], QString("mode=100644 user=weis group=users path=empty type=file size=0"), creationTime); 0532 compareEntryWithTimestamp(listing[5], QString("mode=100755 user= group= path=executableAll type=file size=17"), creationTime); 0533 compareEntryWithTimestamp(listing[6], QString("mode=100644 user= group= path=hugefile type=file size=20000"), creationTime); 0534 compareEntryWithTimestamp(listing[7], QString("mode=100644 user= group= path=mediumfile type=file size=100"), creationTime); 0535 QCOMPARE(listing[8], QString("mode=40777 user=%1 group=%2 path=my type=dir time=").arg(systemUserName).arg(systemGroupName)); 0536 QCOMPARE(listing[9], QString("mode=40777 user=%1 group=%2 path=my/dir type=dir time=").arg(systemUserName).arg(systemGroupName)); 0537 compareEntryWithTimestamp(listing[10], QString("mode=100644 user=dfaure group=hackers path=my/dir/test3 type=file size=28"), creationTime); 0538 compareEntryWithTimestamp(listing[11], QString("mode=100440 user=weis group=users path=test1 type=file size=5"), creationTime); 0539 compareEntryWithTimestamp(listing[12], QString("mode=100644 user=weis group=users path=test2 type=file size=8"), creationTime); 0540 QCOMPARE(listing[13], QString("mode=40777 user=%1 group=%2 path=z type=dir time=").arg(systemUserName).arg(systemGroupName)); 0541 0542 // This one was added with addLocalFile, so ignore mode. 0543 QString str = listing[14]; 0544 str.replace(QRegularExpression(QStringLiteral("mode.*user=")), QStringLiteral("user=")); 0545 0546 compareEntryWithTimestamp(str, QString("user=%1 group=%2 path=z/test3 type=file size=13").arg(owner).arg(group), creationTime); 0547 0548 #ifndef Q_OS_WIN 0549 str = listing[15]; 0550 str.replace(QRegularExpression(QStringLiteral("mode.*path=")), QStringLiteral("path=")); 0551 0552 compareEntryWithTimestamp(str, QString("path=z/test3_symlink type=file size=0 symlink=test3"), creationTime); 0553 #endif 0554 0555 QVERIFY(tar.close()); 0556 } 0557 } 0558 0559 /** 0560 * This tests the decompression using kfilterdev, basically. 0561 * To debug KTarPrivate::fillTempFile(). 0562 * 0563 * @dataProvider setupData 0564 */ 0565 void KArchiveTest::testUncompress() 0566 { 0567 QFETCH(QString, fileName); 0568 QFETCH(QString, mimeType); 0569 0570 // testCreateTar must have been run first. 0571 QVERIFY(QFile::exists(fileName)); 0572 KCompressionDevice filterDev(fileName); 0573 QByteArray buffer; 0574 buffer.resize(8 * 1024); 0575 // qDebug() << "buffer.size()=" << buffer.size(); 0576 QVERIFY(filterDev.open(QIODevice::ReadOnly)); 0577 0578 qint64 totalSize = 0; 0579 qint64 len = -1; 0580 while (!filterDev.atEnd() && len != 0) { 0581 len = filterDev.read(buffer.data(), buffer.size()); 0582 QVERIFY(len >= 0); 0583 totalSize += len; 0584 // qDebug() << "read len=" << len << " totalSize=" << totalSize; 0585 } 0586 filterDev.close(); 0587 // qDebug() << "totalSize=" << totalSize; 0588 QVERIFY(totalSize > 26000); // 27648 here when using gunzip 0589 } 0590 0591 /** 0592 * @dataProvider setupData 0593 */ 0594 void KArchiveTest::testTarFileData() 0595 { 0596 QFETCH(QString, fileName); 0597 0598 // testCreateTar must have been run first. 0599 KTar tar(fileName); 0600 QVERIFY(tar.open(QIODevice::ReadOnly)); 0601 0602 testFileData(&tar); 0603 0604 QVERIFY(tar.close()); 0605 } 0606 0607 /** 0608 * @dataProvider setupData 0609 */ 0610 void KArchiveTest::testTarCopyTo() 0611 { 0612 QFETCH(QString, fileName); 0613 0614 // testCreateTar must have been run first. 0615 KTar tar(fileName); 0616 QVERIFY(tar.open(QIODevice::ReadOnly)); 0617 0618 testCopyTo(&tar); 0619 0620 QVERIFY(tar.close()); 0621 } 0622 0623 /** 0624 * @dataProvider setupData 0625 */ 0626 void KArchiveTest::testTarReadWrite() 0627 { 0628 QFETCH(QString, fileName); 0629 0630 // testCreateTar must have been run first. 0631 KTar tar(fileName); 0632 QVERIFY(tar.open(QIODevice::ReadWrite)); 0633 0634 testReadWrite(&tar); 0635 testFileData(&tar); 0636 0637 QVERIFY(tar.close()); 0638 0639 // Reopen it and check it 0640 { 0641 KTar tar(fileName); 0642 QVERIFY(tar.open(QIODevice::ReadOnly)); 0643 testFileData(&tar); 0644 const KArchiveDirectory *dir = tar.directory(); 0645 const KArchiveEntry *e = dir->entry(QStringLiteral("newfile")); 0646 QVERIFY(e && e->isFile()); 0647 const KArchiveFile *f = (KArchiveFile *)e; 0648 QCOMPARE(f->data().size(), 8); 0649 } 0650 0651 // NOTE This is the last test for this dataset. so cleanup here 0652 QFile::remove(fileName); 0653 } 0654 0655 void KArchiveTest::testTarMaxLength_data() 0656 { 0657 QTest::addColumn<QString>("fileName"); 0658 QTest::newRow("maxlength.tar.gz") << "karchivetest-maxlength.tar.gz"; 0659 } 0660 0661 /** 0662 * @dataProvider testTarMaxLength_data 0663 */ 0664 void KArchiveTest::testTarMaxLength() 0665 { 0666 QFETCH(QString, fileName); 0667 0668 KTar tar(fileName); 0669 0670 QVERIFY(tar.open(QIODevice::WriteOnly)); 0671 0672 // Generate long filenames of each possible length bigger than 98... 0673 // Also exceed 512 byte block size limit to see how well the ././@LongLink 0674 // implementation fares 0675 for (int i = 98; i < 514; i++) { 0676 QString str; 0677 QString num; 0678 str.fill('a', i - 10); 0679 num.setNum(i); 0680 num = num.rightJustified(10, '0'); 0681 tar.writeFile(str + num, "hum"); 0682 } 0683 // Result of this test : works perfectly now (failed at 482 formerly and 0684 // before that at 154). 0685 QVERIFY(tar.close()); 0686 0687 QVERIFY(tar.open(QIODevice::ReadOnly)); 0688 0689 const KArchiveDirectory *dir = tar.directory(); 0690 QVERIFY(dir != nullptr); 0691 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup); 0692 0693 QCOMPARE(listing[0], 0694 QString("mode=100644 user= group= path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000098 " 0695 "type=file size=3")); 0696 QCOMPARE(listing[3], 0697 QString("mode=100644 user= group= path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000101 " 0698 "type=file size=3")); 0699 QCOMPARE(listing[4], 0700 QString("mode=100644 user= group= path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000102 " 0701 "type=file size=3")); 0702 0703 QCOMPARE(listing.count(), 416); 0704 0705 QVERIFY(tar.close()); 0706 0707 // NOTE Cleanup here 0708 QFile::remove(fileName); 0709 } 0710 0711 void KArchiveTest::testTarGlobalHeader() 0712 { 0713 KTar tar(QFINDTESTDATA(QLatin1String("global_header_test.tar.gz"))); 0714 QVERIFY2(tar.open(QIODevice::ReadOnly), "global_header_test.tar.gz"); 0715 0716 const KArchiveDirectory *dir = tar.directory(); 0717 QVERIFY(dir != nullptr); 0718 0719 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup); 0720 0721 QCOMPARE(listing.count(), 2); 0722 0723 QCOMPARE(listing[0], QString("mode=40775 user=root group=root path=Test type=dir")); 0724 QCOMPARE(listing[1], QString("mode=664 user=root group=root path=Test/test.txt type=file size=0")); 0725 0726 QVERIFY(tar.close()); 0727 } 0728 0729 void KArchiveTest::testTarPrefix() 0730 { 0731 KTar tar(QFINDTESTDATA(QLatin1String("tar_prefix_test.tar.gz"))); 0732 QVERIFY2(tar.open(QIODevice::ReadOnly), "tar_prefix_test.tar.gz"); 0733 0734 const KArchiveDirectory *dir = tar.directory(); 0735 QVERIFY(dir != nullptr); 0736 0737 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup); 0738 0739 QCOMPARE(listing[0], QString("mode=40775 user=root group=root path=Test type=dir")); 0740 QCOMPARE(listing[1], QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7 type=dir")); 0741 QCOMPARE(listing[2], QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples type=dir")); 0742 QCOMPARE(listing[3], QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples/generator type=dir")); 0743 QCOMPARE(listing[4], QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples/generator/trolltech_original type=dir")); 0744 QCOMPARE(listing[5], QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples/generator/trolltech_original/java type=dir")); 0745 QCOMPARE(listing[6], QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples/generator/trolltech_original/java/com type=dir")); 0746 QCOMPARE(listing[7], 0747 QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples/generator/trolltech_original/java/com/trolltech type=dir")); 0748 QCOMPARE( 0749 listing[8], 0750 QString("mode=40775 user=root group=root path=Test/qt-jambi-qtjambi-4_7/examples/generator/trolltech_original/java/com/trolltech/examples type=dir")); 0751 QCOMPARE( 0752 listing[9], 0753 QString("mode=664 user=root group=root " 0754 "path=Test/qt-jambi-qtjambi-4_7/examples/generator/trolltech_original/java/com/trolltech/examples/GeneratorExample.html type=file size=43086")); 0755 0756 QCOMPARE(listing.count(), 10); 0757 0758 QVERIFY(tar.close()); 0759 } 0760 0761 void KArchiveTest::testTarDirectoryForgotten() 0762 { 0763 KTar tar(QFINDTESTDATA(QLatin1String("tar_directory_forgotten.tar.gz"))); 0764 QVERIFY2(tar.open(QIODevice::ReadOnly), "tar_directory_forgotten.tar.gz"); 0765 0766 const KArchiveDirectory *dir = tar.directory(); 0767 QVERIFY(dir != nullptr); 0768 0769 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup); 0770 0771 QVERIFY(listing[9].contains("trolltech/examples/generator")); 0772 QVERIFY(listing[10].contains("trolltech/examples/generator/GeneratorExample.html")); 0773 0774 QCOMPARE(listing.count(), 11); 0775 0776 QVERIFY(tar.close()); 0777 } 0778 0779 void KArchiveTest::testTarEmptyFileMissingDir() 0780 { 0781 KTar tar(QFINDTESTDATA(QLatin1String("tar_emptyfile_missingdir.tar.gz"))); 0782 QVERIFY(tar.open(QIODevice::ReadOnly)); 0783 0784 const KArchiveDirectory *dir = tar.directory(); 0785 QVERIFY(dir != nullptr); 0786 0787 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 0788 0789 QCOMPARE(listing[0], QString("mode=40777 path=dir type=dir")); 0790 QCOMPARE(listing[1], QString("mode=40777 path=dir/foo type=dir")); 0791 QCOMPARE(listing[2], QString("mode=644 path=dir/foo/file type=file size=0")); 0792 QCOMPARE(listing.count(), 3); 0793 0794 QVERIFY(tar.close()); 0795 } 0796 0797 void KArchiveTest::testTarRootDir() // bug 309463 0798 { 0799 KTar tar(QFINDTESTDATA(QLatin1String("tar_rootdir.tar.gz"))); 0800 QVERIFY2(tar.open(QIODevice::ReadOnly), qPrintable(tar.fileName())); 0801 0802 const KArchiveDirectory *dir = tar.directory(); 0803 QVERIFY(dir != nullptr); 0804 0805 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup); 0806 // qDebug() << listing.join("\n"); 0807 0808 QVERIFY(listing[0].contains("%{APPNAME}.cpp")); 0809 QVERIFY(listing[1].contains("%{APPNAME}.h")); 0810 QVERIFY(listing[5].contains("main.cpp")); 0811 0812 QCOMPARE(listing.count(), 10); 0813 } 0814 0815 void KArchiveTest::testTarLongNonASCIINames() // bug 266141 0816 { 0817 const QString tarName = QString("karchive-long-non-ascii-names.tar"); 0818 const QString longName = QString::fromUtf8("раз-два-три-четыре-пять-вышел-зайчик-погулять-вдруг-охотник-выбегает-прямо-в-зайчика.txt"); 0819 0820 { 0821 KTar tar(tarName); 0822 QVERIFY(tar.open(QIODevice::WriteOnly)); 0823 QVERIFY(tar.writeFile(longName, "", 0644, "user", "users")); 0824 QVERIFY(tar.close()); 0825 } 0826 0827 { 0828 KTar tar(tarName); 0829 0830 QVERIFY(tar.open(QIODevice::ReadOnly)); 0831 const KArchiveDirectory *dir = tar.directory(); 0832 QVERIFY(dir != nullptr); 0833 0834 const QStringList listing = recursiveListEntries(dir, QString(""), 0); 0835 0836 const QString expectedListingEntry = QString("mode=644 path=") + longName + QString(" type=file size=0"); 0837 0838 QCOMPARE(listing.count(), 1); 0839 0840 QCOMPARE(listing[0], expectedListingEntry); 0841 QVERIFY(tar.close()); 0842 } 0843 } 0844 0845 void KArchiveTest::testTarShortNonASCIINames() // bug 266141 0846 { 0847 KTar tar(QFINDTESTDATA(QString("tar_non_ascii_file_name.tar.gz"))); 0848 0849 QVERIFY(tar.open(QIODevice::ReadOnly)); 0850 const KArchiveDirectory *dir = tar.directory(); 0851 QVERIFY(dir != nullptr); 0852 0853 const QStringList listing = recursiveListEntries(dir, QString(""), 0); 0854 0855 QCOMPARE(listing.count(), 1); 0856 QCOMPARE(listing[0], 0857 QString("mode=644 path=абвгдеёжзийклмнопрстуфхцчшщъыьэюя.txt" 0858 " type=file size=0")); 0859 QVERIFY(tar.close()); 0860 } 0861 0862 void KArchiveTest::testTarDirectoryTwice() // bug 206994 0863 { 0864 KTar tar(QFINDTESTDATA(QLatin1String("tar_directory_twice.tar.gz"))); 0865 QVERIFY(tar.open(QIODevice::ReadOnly)); 0866 0867 const KArchiveDirectory *dir = tar.directory(); 0868 QVERIFY(dir != nullptr); 0869 0870 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), WithUserGroup); 0871 // qDebug() << listing.join("\n"); 0872 0873 QVERIFY(listing[0].contains("path=d")); 0874 QVERIFY(listing[1].contains("path=d/f1.txt")); 0875 QVERIFY(listing[2].contains("path=d/f2.txt")); 0876 0877 QCOMPARE(listing.count(), 3); 0878 } 0879 0880 void KArchiveTest::testTarIgnoreRelativePathOutsideArchive() 0881 { 0882 #if HAVE_BZIP2_SUPPORT 0883 // This test extracts a Tar archive that contains a relative path "../foo" pointing 0884 // outside of the archive directory. For security reasons extractions should only 0885 // be allowed within the extracted directory as long as not specifically asked. 0886 0887 KTar tar(QFINDTESTDATA(QLatin1String("tar_relative_path_outside_archive.tar.bz2"))); 0888 QVERIFY(tar.open(QIODevice::ReadOnly)); 0889 0890 const KArchiveDirectory *dir = tar.directory(); 0891 QTemporaryDir tmpDir; 0892 const QString dirName = tmpDir.path() + "/subdir"; // use a subdir so /tmp/foo doesn't break the test :) 0893 QDir().mkdir(dirName); 0894 0895 QVERIFY(dir->copyTo(dirName)); 0896 QVERIFY(!QFile::exists(dirName + "../foo")); 0897 QVERIFY(QFile::exists(dirName + "/foo")); 0898 #else 0899 QSKIP("Test data is in bz2 format and karchive is built without bzip2 format"); 0900 #endif 0901 } 0902 /// 0903 0904 static const char s_zipFileName[] = "karchivetest.zip"; 0905 static const char s_zipMaxLengthFileName[] = "karchivetest-maxlength.zip"; 0906 static const char s_zipLocaleFileName[] = "karchivetest-locale.zip"; 0907 static const char s_zipMimeType[] = "application/vnd.oasis.opendocument.text"; 0908 0909 void KArchiveTest::testCreateZip() 0910 { 0911 KZip zip(s_zipFileName); 0912 0913 QVERIFY(zip.open(QIODevice::WriteOnly)); 0914 0915 zip.setExtraField(KZip::NoExtraField); 0916 0917 zip.setCompression(KZip::NoCompression); 0918 QByteArray zipMimeType(s_zipMimeType); 0919 zip.writeFile(QStringLiteral("mimetype"), zipMimeType); 0920 zip.setCompression(KZip::DeflateCompression); 0921 0922 writeTestFilesToArchive(&zip); 0923 0924 QVERIFY(zip.close()); 0925 0926 QFile zipFile(QFile::encodeName(s_zipFileName)); 0927 QFileInfo fileInfo(zipFile); 0928 QVERIFY(fileInfo.exists()); 0929 QVERIFY(fileInfo.size() > 300); 0930 0931 // Check that the header with no-compression and no-extrafield worked. 0932 // (This is for the "magic" for koffice documents) 0933 QVERIFY(zipFile.open(QIODevice::ReadOnly)); 0934 QByteArray arr = zipFile.read(4); 0935 QCOMPARE(arr, QByteArray("PK\003\004")); 0936 QVERIFY(zipFile.seek(30)); 0937 arr = zipFile.read(8); 0938 QCOMPARE(arr, QByteArray("mimetype")); 0939 arr = zipFile.read(zipMimeType.size()); 0940 QCOMPARE(arr, zipMimeType); 0941 } 0942 0943 void KArchiveTest::testCreateZipError() 0944 { 0945 // Giving a directory name to kzip must give an error case in close(), see #136630. 0946 // Otherwise we just lose data. 0947 KZip zip(QDir::currentPath()); 0948 0949 QVERIFY(!zip.open(QIODevice::WriteOnly)); 0950 QCOMPARE(zip.errorString(), tr("QSaveFile creation for %1 failed: Filename refers to a directory").arg(QDir::currentPath())); 0951 } 0952 0953 void KArchiveTest::testReadZipError() 0954 { 0955 QFile brokenZip(QStringLiteral("broken.zip")); 0956 QVERIFY(brokenZip.open(QIODevice::WriteOnly)); 0957 0958 // incomplete magic 0959 brokenZip.write(QByteArray("PK\003")); 0960 0961 brokenZip.close(); 0962 { 0963 KZip zip(QStringLiteral("broken.zip")); 0964 0965 QVERIFY(!zip.open(QIODevice::ReadOnly)); 0966 QCOMPARE(zip.errorString(), tr("Invalid ZIP file. Unexpected end of file. (Error code: %1)").arg(1)); 0967 0968 QVERIFY(brokenZip.open(QIODevice::WriteOnly | QIODevice::Append)); 0969 0970 // add rest of magic, but still incomplete header 0971 brokenZip.write(QByteArray("\004\000\000\000\000")); 0972 0973 brokenZip.close(); 0974 0975 QVERIFY(!zip.open(QIODevice::ReadOnly)); 0976 QCOMPARE(zip.errorString(), tr("Invalid ZIP file. Unexpected end of file. (Error code: %1)").arg(4)); 0977 } 0978 0979 QVERIFY(brokenZip.remove()); 0980 } 0981 0982 void KArchiveTest::testReadZip() 0983 { 0984 // testCreateZip must have been run first. 0985 KZip zip(s_zipFileName); 0986 0987 QVERIFY(zip.open(QIODevice::ReadOnly)); 0988 0989 const KArchiveDirectory *dir = zip.directory(); 0990 QVERIFY(dir != nullptr); 0991 0992 // ZIP has no support for per-file user/group, so omit them from the listing 0993 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 0994 0995 #ifndef Q_OS_WIN 0996 QCOMPARE(listing.count(), 17); 0997 #else 0998 QCOMPARE(listing.count(), 16); 0999 #endif 1000 QCOMPARE(listing[0], QString("mode=40755 path=aaaemptydir type=dir")); 1001 QCOMPARE(listing[1], QString("mode=40777 path=dir type=dir")); 1002 QCOMPARE(listing[2], QString("mode=40777 path=dir/subdir type=dir")); 1003 QCOMPARE(listing[3], QString("mode=100644 path=dir/subdir/mediumfile2 type=file size=100")); 1004 QCOMPARE(listing[4], QString("mode=100644 path=empty type=file size=0")); 1005 QCOMPARE(listing[5], QString("mode=100755 path=executableAll type=file size=17")); 1006 QCOMPARE(listing[6], QString("mode=100644 path=hugefile type=file size=20000")); 1007 QCOMPARE(listing[7], QString("mode=100644 path=mediumfile type=file size=100")); 1008 QCOMPARE(listing[8], QString("mode=100644 path=mimetype type=file size=%1").arg(strlen(s_zipMimeType))); 1009 QCOMPARE(listing[9], QString("mode=40777 path=my type=dir")); 1010 QCOMPARE(listing[10], QString("mode=40777 path=my/dir type=dir")); 1011 QCOMPARE(listing[11], QString("mode=100644 path=my/dir/test3 type=file size=28")); 1012 QCOMPARE(listing[12], QString("mode=100440 path=test1 type=file size=5")); 1013 QCOMPARE(listing[13], QString("mode=100644 path=test2 type=file size=8")); 1014 QCOMPARE(listing[14], QString("mode=40777 path=z type=dir")); 1015 // This one was added with addLocalFile, so ignore mode 1016 QString str = listing[15]; 1017 str.replace(QRegularExpression(QStringLiteral("mode.*path=")), QStringLiteral("path=")); 1018 QCOMPARE(str, QString("path=z/test3 type=file size=13")); 1019 #ifndef Q_OS_WIN 1020 str = listing[16]; 1021 str.replace(QRegularExpression(QStringLiteral("mode.*path=")), QStringLiteral("path=")); 1022 QCOMPARE(str, QString("path=z/test3_symlink type=file size=5 symlink=test3")); 1023 #endif 1024 1025 QVERIFY(zip.close()); 1026 } 1027 1028 void KArchiveTest::testZipFileData() 1029 { 1030 // testCreateZip must have been run first. 1031 KZip zip(s_zipFileName); 1032 QVERIFY(zip.open(QIODevice::ReadOnly)); 1033 1034 testFileData(&zip); 1035 1036 QVERIFY(zip.close()); 1037 } 1038 1039 void KArchiveTest::testZipCopyTo() 1040 { 1041 // testCreateZip must have been run first. 1042 KZip zip(s_zipFileName); 1043 QVERIFY(zip.open(QIODevice::ReadOnly)); 1044 1045 testCopyTo(&zip); 1046 1047 QVERIFY(zip.close()); 1048 } 1049 1050 void KArchiveTest::testZipMaxLength() 1051 { 1052 KZip zip(s_zipMaxLengthFileName); 1053 1054 QVERIFY(zip.open(QIODevice::WriteOnly)); 1055 1056 // Similar to testTarMaxLength just to make sure, but of course zip doesn't have 1057 // those limitations in the first place. 1058 for (int i = 98; i < 514; i++) { 1059 QString str; 1060 QString num; 1061 str.fill('a', i - 10); 1062 num.setNum(i); 1063 num = num.rightJustified(10, '0'); 1064 zip.writeFile(str + num, "hum"); 1065 } 1066 QVERIFY(zip.close()); 1067 1068 QVERIFY(zip.open(QIODevice::ReadOnly)); 1069 1070 const KArchiveDirectory *dir = zip.directory(); 1071 QVERIFY(dir != nullptr); 1072 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1073 1074 QCOMPARE(listing[0], 1075 QString("mode=100644 path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000098 type=file size=3")); 1076 QCOMPARE( 1077 listing[3], 1078 QString("mode=100644 path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000101 type=file size=3")); 1079 QCOMPARE( 1080 listing[4], 1081 QString("mode=100644 path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000102 type=file size=3")); 1082 1083 QCOMPARE(listing.count(), 514 - 98); 1084 1085 QVERIFY(zip.close()); 1086 } 1087 1088 void KArchiveTest::testZipWithNonLatinFileNames() 1089 { 1090 KZip zip(s_zipLocaleFileName); 1091 1092 QVERIFY(zip.open(QIODevice::WriteOnly)); 1093 1094 const QByteArray fileData("Test of data with a russian file name"); 1095 const QString fileName = QString::fromUtf8("Архитектура.okular"); 1096 const QString recodedFileName = QFile::decodeName(QFile::encodeName(fileName)); 1097 QVERIFY(zip.writeFile(fileName, fileData)); 1098 1099 QVERIFY(zip.close()); 1100 1101 QVERIFY(zip.open(QIODevice::ReadOnly)); 1102 1103 const KArchiveDirectory *dir = zip.directory(); 1104 QVERIFY(dir != nullptr); 1105 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1106 1107 QCOMPARE(listing.count(), 1); 1108 QCOMPARE(listing[0], QString::fromUtf8("mode=100644 path=%1 type=file size=%2").arg(recodedFileName).arg(fileData.size())); 1109 1110 const KArchiveFile *fileEntry = static_cast<const KArchiveFile *>(dir->entry(dir->entries()[0])); 1111 QCOMPARE(fileEntry->data(), fileData); 1112 } 1113 1114 void KArchiveTest::testZipWithOverwrittenFileName() 1115 { 1116 KZip zip(s_zipFileName); 1117 1118 QVERIFY(zip.open(QIODevice::WriteOnly)); 1119 1120 const QByteArray fileData1("There could be a fire, if there is smoke."); 1121 const QString fileName = QStringLiteral("wisdom"); 1122 QVERIFY(zip.writeFile(fileName, fileData1, 0100644, "konqi", "dragons")); 1123 1124 // now overwrite it 1125 const QByteArray fileData2("If there is smoke, there could be a fire."); 1126 QVERIFY(zip.writeFile(fileName, fileData2, 0100644, "konqi", "dragons")); 1127 1128 QVERIFY(zip.close()); 1129 1130 QVERIFY(zip.open(QIODevice::ReadOnly)); 1131 1132 const KArchiveDirectory *dir = zip.directory(); 1133 QVERIFY(dir != nullptr); 1134 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1135 1136 QCOMPARE(listing.count(), 1); 1137 QCOMPARE(listing[0], QString::fromUtf8("mode=100644 path=%1 type=file size=%2").arg(fileName).arg(fileData2.size())); 1138 1139 const KArchiveFile *fileEntry = static_cast<const KArchiveFile *>(dir->entry(dir->entries()[0])); 1140 QCOMPARE(fileEntry->data(), fileData2); 1141 } 1142 1143 static bool writeFile(const QString &dirName, const QString &fileName, const QByteArray &data) 1144 { 1145 Q_ASSERT(dirName.endsWith('/')); 1146 QFile file(dirName + fileName); 1147 if (!file.open(QIODevice::WriteOnly)) { 1148 return false; 1149 } 1150 file.write(data); 1151 return true; 1152 } 1153 1154 void KArchiveTest::testZipAddLocalDirectory() 1155 { 1156 // Prepare local dir 1157 QTemporaryDir tmpDir; 1158 const QString dirName = tmpDir.path() + '/'; 1159 1160 const QByteArray file1Data = "Hello Shantanu"; 1161 const QString file1 = QStringLiteral("file1"); 1162 QVERIFY(writeFile(dirName, file1, file1Data)); 1163 1164 const QString emptyDir = QStringLiteral("emptyDir"); 1165 QDir(dirName).mkdir(emptyDir); 1166 1167 { 1168 KZip zip(s_zipFileName); 1169 1170 QVERIFY(zip.open(QIODevice::WriteOnly)); 1171 QVERIFY(zip.addLocalDirectory(dirName, ".")); 1172 QVERIFY(zip.close()); 1173 } 1174 { 1175 KZip zip(s_zipFileName); 1176 1177 QVERIFY(zip.open(QIODevice::ReadOnly)); 1178 1179 const KArchiveDirectory *dir = zip.directory(); 1180 QVERIFY(dir != nullptr); 1181 1182 const KArchiveEntry *e = dir->entry(file1); 1183 QVERIFY(e && e->isFile()); 1184 const KArchiveFile *f = static_cast<const KArchiveFile *>(e); 1185 QCOMPARE(f->data(), file1Data); 1186 1187 const KArchiveEntry *empty = dir->entry(emptyDir); 1188 QVERIFY(empty && empty->isDirectory()); 1189 } 1190 } 1191 1192 void KArchiveTest::testZipReadRedundantDataDescriptor_data() 1193 { 1194 QTest::addColumn<QString>("fileName"); 1195 QTest::newRow("noSignature") << "data/redundantDataDescriptorsNoSignature.zip"; 1196 QTest::newRow("withSignature") << "data/redundantDataDescriptorsWithSignature.zip"; 1197 } 1198 1199 /** 1200 * @dataProvider testZipReadRedundantDataDescriptor_data 1201 */ 1202 void KArchiveTest::testZipReadRedundantDataDescriptor() 1203 { 1204 QFETCH(QString, fileName); 1205 1206 const QString redundantDataDescriptorZipFileName = QFINDTESTDATA(fileName); 1207 QVERIFY(!redundantDataDescriptorZipFileName.isEmpty()); 1208 1209 KZip zip(redundantDataDescriptorZipFileName); 1210 1211 QVERIFY(zip.open(QIODevice::ReadOnly)); 1212 1213 const KArchiveDirectory *dir = zip.directory(); 1214 QVERIFY(dir != nullptr); 1215 1216 const QByteArray fileData("aaaaaaaaaaaaaaa"); 1217 1218 // ZIP has no support for per-file user/group, so omit them from the listing 1219 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1220 1221 QCOMPARE(listing.count(), 2); 1222 QCOMPARE(listing[0], QString::fromUtf8("mode=100644 path=compressed type=file size=%2").arg(fileData.size())); 1223 QCOMPARE(listing[1], QString::fromUtf8("mode=100644 path=uncompressed type=file size=%2").arg(fileData.size())); 1224 1225 const KArchiveFile *fileEntry = static_cast<const KArchiveFile *>(dir->entry(dir->entries()[0])); 1226 QCOMPARE(fileEntry->data(), fileData); 1227 fileEntry = static_cast<const KArchiveFile *>(dir->entry(dir->entries()[1])); 1228 QCOMPARE(fileEntry->data(), fileData); 1229 } 1230 1231 void KArchiveTest::testZipDirectoryPermissions() 1232 { 1233 QString fileName = QFINDTESTDATA("data/dirpermissions.zip"); 1234 QVERIFY(!fileName.isEmpty()); 1235 1236 KZip zip(fileName); 1237 1238 QVERIFY(zip.open(QIODevice::ReadOnly)); 1239 const KArchiveDirectory *dir = zip.directory(); 1240 const QStringList listing = recursiveListEntries(dir, QString(), 0); 1241 QCOMPARE(listing.join(' '), QString::fromUtf8("mode=40700 path=700 type=dir mode=40750 path=750 type=dir mode=40755 path=755 type=dir")); 1242 } 1243 1244 void KArchiveTest::testZipWithinZip() 1245 { 1246 QString fileName = QFINDTESTDATA("data/zip_within_zip.zip"); 1247 QVERIFY(!fileName.isEmpty()); 1248 1249 KZip zip(fileName); 1250 1251 QVERIFY(zip.open(QIODevice::ReadOnly)); 1252 const KArchiveDirectory *dir = zip.directory(); 1253 const QStringList listing = recursiveListEntries(dir, QString(), 0); 1254 QCOMPARE(listing.count(), 2); 1255 QCOMPARE(listing[0], QString::fromUtf8("mode=100644 path=foo type=file size=7")); 1256 QCOMPARE(listing[1], QString::fromUtf8("mode=100644 path=test.epub type=file size=525154")); 1257 } 1258 1259 void KArchiveTest::testZipUnusualButValid() 1260 { 1261 QString fileName = QFINDTESTDATA("data/unusual_but_valid_364071.zip"); 1262 QVERIFY(!fileName.isEmpty()); 1263 1264 KZip zip(fileName); 1265 1266 QVERIFY(zip.open(QIODevice::ReadOnly)); 1267 const KArchiveDirectory *dir = zip.directory(); 1268 const QStringList listing = recursiveListEntries(dir, QString(), 0); 1269 QCOMPARE(listing.join(' '), QLatin1String("mode=40744 path=test type=dir mode=744 path=test/os-release type=file size=199")); 1270 } 1271 1272 void KArchiveTest::testZipDuplicateNames() 1273 { 1274 QString fileName = QFINDTESTDATA("data/out.epub"); 1275 QVERIFY(!fileName.isEmpty()); 1276 1277 KZip zip(fileName); 1278 1279 QVERIFY(zip.open(QIODevice::ReadOnly)); 1280 1281 int metaInfCount = 0; 1282 for (const QString &entryName : zip.directory()->entries()) { 1283 if (entryName.startsWith("META-INF")) { 1284 metaInfCount++; 1285 } 1286 } 1287 1288 QVERIFY2(metaInfCount == 1, "Archive root directory contains duplicates"); 1289 } 1290 1291 void KArchiveTest::testZip64() 1292 { 1293 QString fileName = QFINDTESTDATA("data/zip64.pkpass"); 1294 QVERIFY(!fileName.isEmpty()); 1295 1296 KZip zip(fileName); 1297 QVERIFY(zip.open(QIODevice::ReadOnly)); 1298 1299 // NOTE the actual content of this file has been wiped, we can only verify the file meta data here 1300 QCOMPARE(zip.directory()->entries().size(), 7); 1301 auto entry = static_cast<const KZipFileEntry *>(zip.directory()->entry(QStringLiteral("manifest.json"))); 1302 QVERIFY(entry); 1303 QCOMPARE(entry->size(), 305); 1304 QCOMPARE(entry->compressedSize(), 194); 1305 QCOMPARE(entry->position(), 21417); 1306 entry = static_cast<const KZipFileEntry *>(zip.directory()->entry(QStringLiteral("logo.png"))); 1307 QVERIFY(entry); 1308 QCOMPARE(entry->size(), 3589); 1309 QCOMPARE(entry->compressedSize(), 3594); 1310 QCOMPARE(entry->position(), 8943); 1311 } 1312 1313 void KArchiveTest::testRcc() 1314 { 1315 const QString rccFile = QFINDTESTDATA("runtime_resource.rcc"); // was copied from qtbase/tests/auto/corelib/io/qresourceengine 1316 QVERIFY(!rccFile.isEmpty()); 1317 KRcc rcc(rccFile); 1318 QVERIFY(rcc.open(QIODevice::ReadOnly)); 1319 const KArchiveDirectory *rootDir = rcc.directory(); 1320 QVERIFY(rootDir != nullptr); 1321 const KArchiveEntry *rrEntry = rootDir->entry(QStringLiteral("runtime_resource")); 1322 QVERIFY(rrEntry && rrEntry->isDirectory()); 1323 const KArchiveDirectory *rrDir = static_cast<const KArchiveDirectory *>(rrEntry); 1324 const KArchiveEntry *fileEntry = rrDir->entry(QStringLiteral("search_file.txt")); 1325 QVERIFY(fileEntry && fileEntry->isFile()); 1326 const KArchiveFile *searchFile = static_cast<const KArchiveFile *>(fileEntry); 1327 const QByteArray fileData = searchFile->data(); 1328 QCOMPARE(QString::fromLatin1(fileData), QString::fromLatin1("root\n")); 1329 } 1330 1331 void KArchiveTest::testAr() 1332 { 1333 const QString artestFile = QFINDTESTDATA("data/artest.a"); 1334 KAr ar(artestFile); 1335 1336 QVERIFY(ar.open(QIODevice::ReadOnly)); 1337 1338 const KArchiveDirectory *dir = ar.directory(); 1339 QVERIFY(dir != nullptr); 1340 1341 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1342 1343 const QStringList expected = {"mode=100644 path=at_quick_exit.oS type=file size=3456", 1344 "mode=100644 path=atexit.oS type=file size=3436", 1345 "mode=100644 path=elf-init.oS type=file size=3288", 1346 "mode=100644 path=fstat.oS type=file size=3296", 1347 "mode=100644 path=fstat64.oS type=file size=3304", 1348 "mode=100644 path=fstatat.oS type=file size=3352", 1349 "mode=100644 path=fstatat64.oS type=file size=3380", 1350 "mode=100644 path=lstat.oS type=file size=3320", 1351 "mode=100644 path=lstat64.oS type=file size=3332", 1352 "mode=100644 path=mknod.oS type=file size=2840", 1353 "mode=100644 path=mknodat.oS type=file size=2848", 1354 "mode=100644 path=stack_chk_fail_local.oS type=file size=2288", 1355 "mode=100644 path=stat.oS type=file size=3316", 1356 "mode=100644 path=stat64.oS type=file size=3312", 1357 "mode=100644 path=warning-nop.oS type=file size=1976"}; 1358 1359 QCOMPARE(listing.count(), expected.count()); 1360 QCOMPARE(listing, expected); 1361 1362 QVERIFY(ar.close()); 1363 } 1364 1365 /** 1366 * @see QTest::cleanupTestCase() 1367 */ 1368 void KArchiveTest::cleanupTestCase() 1369 { 1370 QFile::remove(s_zipMaxLengthFileName); 1371 QFile::remove(s_zipFileName); 1372 QFile::remove(s_zipLocaleFileName); 1373 #ifndef Q_OS_WIN 1374 QFile::remove(QStringLiteral("test3_symlink")); 1375 #endif 1376 } 1377 1378 /// 1379 1380 #if HAVE_XZ_SUPPORT 1381 1382 /** 1383 * Prepares dataset for archive filter tests 1384 */ 1385 void KArchiveTest::setup7ZipData() 1386 { 1387 QTest::addColumn<QString>("fileName"); 1388 QTest::newRow(".7z") << "karchivetest.7z"; 1389 } 1390 1391 /** 1392 * @dataProvider testCreate7Zip_data 1393 */ 1394 void KArchiveTest::testCreate7Zip() 1395 { 1396 QFETCH(QString, fileName); 1397 1398 QBENCHMARK { 1399 K7Zip k7zip(fileName); 1400 QVERIFY(k7zip.open(QIODevice::WriteOnly)); 1401 1402 writeTestFilesToArchive(&k7zip); 1403 1404 QVERIFY(k7zip.close()); 1405 1406 QFileInfo fileInfo(QFile::encodeName(fileName)); 1407 QVERIFY(fileInfo.exists()); 1408 // qDebug() << "fileInfo.size()" << fileInfo.size(); 1409 // We can't check for an exact size because of the addLocalFile, whose data is system-dependent 1410 QVERIFY(fileInfo.size() > 390); 1411 } 1412 } 1413 1414 /** 1415 * @dataProvider setupData 1416 */ 1417 void KArchiveTest::testRead7Zip() // testCreate7Zip must have been run first. 1418 { 1419 QFETCH(QString, fileName); 1420 1421 QBENCHMARK { 1422 K7Zip k7zip(fileName); 1423 1424 QVERIFY(k7zip.open(QIODevice::ReadOnly)); 1425 1426 const KArchiveDirectory *dir = k7zip.directory(); 1427 QVERIFY(dir != nullptr); 1428 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1429 1430 #ifndef Q_OS_WIN 1431 QCOMPARE(listing.count(), 16); 1432 #else 1433 QCOMPARE(listing.count(), 15); 1434 #endif 1435 QCOMPARE(listing[0], QString("mode=40755 path=aaaemptydir type=dir")); 1436 QCOMPARE(listing[1], QString("mode=40777 path=dir type=dir")); 1437 QCOMPARE(listing[2], QString("mode=40777 path=dir/subdir type=dir")); 1438 QCOMPARE(listing[3], QString("mode=100644 path=dir/subdir/mediumfile2 type=file size=100")); 1439 QCOMPARE(listing[4], QString("mode=100644 path=empty type=file size=0")); 1440 QCOMPARE(listing[5], QString("mode=100755 path=executableAll type=file size=17")); 1441 QCOMPARE(listing[6], QString("mode=100644 path=hugefile type=file size=20000")); 1442 QCOMPARE(listing[7], QString("mode=100644 path=mediumfile type=file size=100")); 1443 QCOMPARE(listing[8], QString("mode=40777 path=my type=dir")); 1444 QCOMPARE(listing[9], QString("mode=40777 path=my/dir type=dir")); 1445 QCOMPARE(listing[10], QString("mode=100644 path=my/dir/test3 type=file size=28")); 1446 QCOMPARE(listing[11], QString("mode=100440 path=test1 type=file size=5")); 1447 QCOMPARE(listing[12], QString("mode=100644 path=test2 type=file size=8")); 1448 QCOMPARE(listing[13], QString("mode=40777 path=z type=dir")); 1449 // This one was added with addLocalFile, so ignore mode/user/group. 1450 QString str = listing[14]; 1451 str.replace(QRegularExpression(QStringLiteral("mode.*path=")), QStringLiteral("path=")); 1452 QCOMPARE(str, QString("path=z/test3 type=file size=13")); 1453 #ifndef Q_OS_WIN 1454 str = listing[15]; 1455 str.replace(QRegularExpression(QStringLiteral("mode.*path=")), QStringLiteral("path=")); 1456 QCOMPARE(str, QString("path=z/test3_symlink type=file size=0 symlink=test3")); 1457 #endif 1458 1459 QVERIFY(k7zip.close()); 1460 } 1461 } 1462 1463 /** 1464 * @dataProvider setupData 1465 */ 1466 void KArchiveTest::test7ZipFileData() 1467 { 1468 QFETCH(QString, fileName); 1469 1470 // testCreate7Zip must have been run first. 1471 K7Zip k7zip(fileName); 1472 QVERIFY(k7zip.open(QIODevice::ReadOnly)); 1473 1474 testFileData(&k7zip); 1475 1476 QVERIFY(k7zip.close()); 1477 } 1478 1479 /** 1480 * @dataProvider setupData 1481 */ 1482 void KArchiveTest::test7ZipCopyTo() 1483 { 1484 QFETCH(QString, fileName); 1485 1486 // testCreateTar must have been run first. 1487 K7Zip k7zip(fileName); 1488 QVERIFY(k7zip.open(QIODevice::ReadOnly)); 1489 1490 testCopyTo(&k7zip); 1491 1492 QVERIFY(k7zip.close()); 1493 } 1494 1495 /** 1496 * @dataProvider setupData 1497 */ 1498 void KArchiveTest::test7ZipReadWrite() 1499 { 1500 QFETCH(QString, fileName); 1501 1502 // testCreate7zip must have been run first. 1503 K7Zip k7zip(fileName); 1504 QVERIFY(k7zip.open(QIODevice::ReadWrite)); 1505 1506 testReadWrite(&k7zip); 1507 testFileData(&k7zip); 1508 1509 QVERIFY(k7zip.close()); 1510 1511 // Reopen it and check it 1512 { 1513 K7Zip k7zip(fileName); 1514 QVERIFY(k7zip.open(QIODevice::ReadOnly)); 1515 testFileData(&k7zip); 1516 const KArchiveDirectory *dir = k7zip.directory(); 1517 const KArchiveEntry *e = dir->entry(QStringLiteral("newfile")); 1518 QVERIFY(e && e->isFile()); 1519 const KArchiveFile *f = (KArchiveFile *)e; 1520 QCOMPARE(f->data().size(), 8); 1521 } 1522 1523 // NOTE This is the last test for this dataset. so cleanup here 1524 QFile::remove(fileName); 1525 } 1526 1527 /** 1528 * @dataProvider test7ZipMaxLength_data 1529 */ 1530 void KArchiveTest::test7ZipMaxLength() 1531 { 1532 QFETCH(QString, fileName); 1533 1534 K7Zip k7zip(fileName); 1535 1536 QVERIFY(k7zip.open(QIODevice::WriteOnly)); 1537 1538 // Generate long filenames of each possible length bigger than 98... 1539 for (int i = 98; i < 514; i++) { 1540 QString str; 1541 QString num; 1542 str.fill('a', i - 10); 1543 num.setNum(i); 1544 num = num.rightJustified(10, '0'); 1545 k7zip.writeFile(str + num, "hum"); 1546 } 1547 QVERIFY(k7zip.close()); 1548 1549 QVERIFY(k7zip.open(QIODevice::ReadOnly)); 1550 1551 const KArchiveDirectory *dir = k7zip.directory(); 1552 QVERIFY(dir != nullptr); 1553 const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); 1554 1555 QCOMPARE(listing[0], 1556 QString("mode=100644 path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000098 type=file size=3")); 1557 QCOMPARE( 1558 listing[3], 1559 QString("mode=100644 path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000101 type=file size=3")); 1560 QCOMPARE( 1561 listing[4], 1562 QString("mode=100644 path=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000102 type=file size=3")); 1563 1564 QCOMPARE(listing.count(), 416); 1565 1566 QVERIFY(k7zip.close()); 1567 1568 // NOTE Cleanup here 1569 QFile::remove(fileName); 1570 } 1571 #endif 1572 1573 #include "moc_karchivetest.cpp"