Hello community, here is the log from the commit of package karchive for openSUSE:Factory checked in at 2019-06-22 11:07:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/karchive (Old) and /work/SRC/openSUSE:Factory/.karchive.new.4615 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "karchive" Sat Jun 22 11:07:55 2019 rev:67 rq:710717 version:5.59.0 Changes: -------- --- /work/SRC/openSUSE:Factory/karchive/karchive.changes 2019-05-21 10:24:58.299561832 +0200 +++ /work/SRC/openSUSE:Factory/.karchive.new.4615/karchive.changes 2019-06-22 11:10:02.360395474 +0200 @@ -1,0 +2,25 @@ +Sun Jun 09 07:35:11 UTC 2019 - lbeltr...@kde.org + +- Update to 5.59.0 + * New feature release + * For more details please see: + * https://www.kde.org/announcements/kde-frameworks-5.59.0.php +- Changes since 5.58.0: + * KCompressionDevice::seek: Fix previous fix ^_^ + * Test reading and seeking in KCompressionDevice + * KCompressionDevice: Remove bIgnoreData + * autotests: more portable way of setting the locale encoding, to fix Windows CI + * KAr: fix out-of-bounds read (on invalid input) by porting to QByteArray + * KAr: minor code cleanups + * autotests: fixes for Windows and utf8 literals + * KAr: fix parsing of long filenames with Qt-5.10 + * AR fix: the permissions are in octal, not decimal. + * KAr: update test file to cover the longfilename table code + * Add KArTest based on KTarTest + * KAr::openArchive: Also check ar_longnamesIndex is not < 0 + * KAr::openArchive: Fix invalid memory access on broken files + * KAr::openArchive: Protect against Heap-buffer-overflow in broken files + * Fix KAr::openArchive with older Qt + * KTar::KTarPrivate::readLonglink: Fix crash in malformed files + +------------------------------------------------------------------- Old: ---- karchive-5.58.0.tar.xz New: ---- karchive-5.59.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ karchive.spec ++++++ --- /var/tmp/diff_new_pack.rTRpV5/_old 2019-06-22 11:10:03.168396665 +0200 +++ /var/tmp/diff_new_pack.rTRpV5/_new 2019-06-22 11:10:03.172396670 +0200 @@ -17,13 +17,13 @@ %define lname libKF5Archive5 -%define _tar_path 5.58 +%define _tar_path 5.59 # Full KF5 version (e.g. 5.33.0) %{!?_kf5_version: %global _kf5_version %{version}} # Last major and minor KF5 version (e.g. 5.33) %{!?_kf5_bugfix_version: %define _kf5_bugfix_version %(echo %{_kf5_version} | awk -F. '{print $1"."$2}')} Name: karchive -Version: 5.58.0 +Version: 5.59.0 Release: 0 Summary: Qt 5 addon providing access to numerous types of archives License: LGPL-2.1-or-later ++++++ karchive-5.58.0.tar.xz -> karchive-5.59.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/.gitignore new/karchive-5.59.0/.gitignore --- old/karchive-5.58.0/.gitignore 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/.gitignore 2019-06-01 18:36:00.000000000 +0200 @@ -1,6 +1,5 @@ # Ignore the following files *~ -*.[oa] *.diff *.kate-swp *.kdev4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/CMakeLists.txt new/karchive-5.59.0/CMakeLists.txt --- old/karchive-5.58.0/CMakeLists.txt 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/CMakeLists.txt 2019-06-01 18:36:00.000000000 +0200 @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.5) -set(KF5_VERSION "5.58.0") # handled by release scripts +set(KF5_VERSION "5.59.0") # handled by release scripts project(KArchive VERSION ${KF5_VERSION}) include(FeatureSummary) -find_package(ECM 5.58.0 NO_MODULE) +find_package(ECM 5.59.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) Binary files old/karchive-5.58.0/autotests/data/artest.a and new/karchive-5.59.0/autotests/data/artest.a differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/autotests/karchivetest.cpp new/karchive-5.59.0/autotests/karchivetest.cpp --- old/karchive-5.58.0/autotests/karchivetest.cpp 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/autotests/karchivetest.cpp 2019-06-01 18:36:00.000000000 +0200 @@ -19,6 +19,7 @@ */ #include "karchivetest.h" +#include <kar.h> #include <ktar.h> #include <kzip.h> #include <k7zip.h> @@ -46,7 +47,8 @@ void initLocale() { - qputenv("LC_ALL", "en_US.UTF-8"); // KArchive uses QFile::decodeName, and our tests use utf8 encoding for filenames + // KArchive uses QFile::decodeName, and our tests use utf8 encoding for filenames + QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8")); } Q_CONSTRUCTOR_FUNCTION(initLocale) @@ -798,8 +800,7 @@ { const QString tarName = QString("karchive-long-non-ascii-names.tar"); const QString longName = - QString("раз-два-три-четыре-пять-вышел-зайчик-погулять-вдруг-охотник-" - "выбегает-прямо-в-зайчика.txt"); + QString::fromUtf8("раз-два-три-четыре-пять-вышел-зайчик-погулять-вдруг-охотник-выбегает-прямо-в-зайчика.txt"); { KTar tar(tarName); @@ -1077,7 +1078,7 @@ QVERIFY(zip.open(QIODevice::WriteOnly)); const QByteArray fileData("Test of data with a russian file name"); - const QString fileName = QStringLiteral("Архитектура.okular"); + const QString fileName = QString::fromUtf8("Архитектура.okular"); const QString recodedFileName = QFile::decodeName(QFile::encodeName(fileName)); QVERIFY(zip.writeFile(fileName, fileData)); @@ -1271,6 +1272,42 @@ QCOMPARE(QString::fromLatin1(fileData), QString::fromLatin1("root\n")); } +void KArchiveTest::testAr() +{ + const QString artestFile = QFINDTESTDATA("data/artest.a"); + KAr ar(artestFile); + + QVERIFY(ar.open(QIODevice::ReadOnly)); + + const KArchiveDirectory *dir = ar.directory(); + QVERIFY(dir != nullptr); + + const QStringList listing = recursiveListEntries(dir, QLatin1String(""), 0); + + const QStringList expected = { + "mode=100644 path=at_quick_exit.oS type=file size=3456", + "mode=100644 path=atexit.oS type=file size=3436", + "mode=100644 path=elf-init.oS type=file size=3288", + "mode=100644 path=fstat.oS type=file size=3296", + "mode=100644 path=fstat64.oS type=file size=3304", + "mode=100644 path=fstatat.oS type=file size=3352", + "mode=100644 path=fstatat64.oS type=file size=3380", + "mode=100644 path=lstat.oS type=file size=3320", + "mode=100644 path=lstat64.oS type=file size=3332", + "mode=100644 path=mknod.oS type=file size=2840", + "mode=100644 path=mknodat.oS type=file size=2848", + "mode=100644 path=stack_chk_fail_local.oS type=file size=2288", + "mode=100644 path=stat.oS type=file size=3316", + "mode=100644 path=stat64.oS type=file size=3312", + "mode=100644 path=warning-nop.oS type=file size=1976" + }; + + QCOMPARE(listing.count(), expected.count()); + QCOMPARE(listing, expected); + + QVERIFY(ar.close()); +} + /** * @see QTest::cleanupTestCase() */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/autotests/karchivetest.h new/karchive-5.59.0/autotests/karchivetest.h --- old/karchive-5.58.0/autotests/karchivetest.h 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/autotests/karchivetest.h 2019-06-01 18:36:00.000000000 +0200 @@ -99,6 +99,8 @@ void testRcc(); + void testAr(); + #if HAVE_XZ_SUPPORT void testCreate7Zip_data() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/autotests/kcompressiondevicetest.cpp new/karchive-5.59.0/autotests/kcompressiondevicetest.cpp --- old/karchive-5.58.0/autotests/kcompressiondevicetest.cpp 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/autotests/kcompressiondevicetest.cpp 2019-06-01 18:36:00.000000000 +0200 @@ -18,6 +18,7 @@ */ #include "kcompressiondevicetest.h" +#include "kcompressiondevice_p.h" #include <config-compression.h> @@ -190,3 +191,39 @@ // THEN QCOMPARE(int(dev.error()), int(QFileDevice::WriteError)); } + +void KCompressionDeviceTest::testSeekReadUncompressedBuffer_data() +{ + QTest::addColumn<int>("dataSize"); + QTest::addColumn<int>("realDataPos"); + QTest::newRow("1.5buffer") << BUFFER_SIZE + BUFFER_SIZE / 2 << BUFFER_SIZE; + QTest::newRow("5seekbuffer") << 5 * SEEK_BUFFER_SIZE << 4 * SEEK_BUFFER_SIZE; +} + +void KCompressionDeviceTest::testSeekReadUncompressedBuffer() +{ + QFETCH(int, dataSize); + QFETCH(int, realDataPos); + + QByteArray ba(dataSize, 0); + + // all data is zero except after realDataPos that it's 0 to 9 + for (int i = 0; i < 10; ++i) { + ba[realDataPos + i] = i; + } + + QBuffer b; + b.setData(ba); + QVERIFY(b.open(QIODevice::ReadOnly)); + + KCompressionDevice kcd(&b, false, KCompressionDevice::GZip); + QVERIFY(kcd.open(QIODevice::ReadOnly)); + QVERIFY(kcd.seek(realDataPos)); + + // the 10 bytes after realDataPos should be 0 to 9 + const QByteArray kcdData = kcd.read(10); + QCOMPARE(kcdData.size(), 10); + for (int i = 0; i < kcdData.size(); ++i) { + QCOMPARE(kcdData[i], i); + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/autotests/kcompressiondevicetest.h new/karchive-5.59.0/autotests/kcompressiondevicetest.h --- old/karchive-5.58.0/autotests/kcompressiondevicetest.h 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/autotests/kcompressiondevicetest.h 2019-06-01 18:36:00.000000000 +0200 @@ -57,6 +57,9 @@ void testWriteErrorOnOpen(); void testWriteErrorOnClose(); + + void testSeekReadUncompressedBuffer_data(); + void testSeekReadUncompressedBuffer(); }; #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/src/kar.cpp new/karchive-5.59.0/src/kar.cpp --- old/karchive-5.58.0/src/kar.cpp 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/src/kar.cpp 2019-06-01 18:36:00.000000000 +0200 @@ -112,64 +112,69 @@ return false; } - char *ar_longnames = nullptr; + QByteArray ar_longnames; while (! dev->atEnd()) { QByteArray ar_header; - ar_header.resize(61); + ar_header.resize(60); dev->seek(dev->pos() + (2 - (dev->pos() % 2)) % 2); // Ar headers are padded to byte boundary if (dev->read(ar_header.data(), 60) != 60) { // Read ar header - //qCWarning(KArchiveLog) << "Couldn't read header"; - delete[] ar_longnames; - //return false; + qCWarning(KArchiveLog) << "Couldn't read header"; return true; // Probably EOF / trailing junk } if (!ar_header.endsWith("`\n")) { // Check header magic // krazy:exclude=strings setErrorString(tr("Invalid magic")); - delete[] ar_longnames; return false; } QByteArray name = ar_header.mid(0, 16); // Process header - const int date = ar_header.mid(16, 12).toInt(); - //const int uid = ar_header.mid( 28, 6 ).toInt(); - //const int gid = ar_header.mid( 34, 6 ).toInt(); - const int mode = ar_header.mid(40, 8).toInt(); - const qint64 size = ar_header.mid(48, 10).toInt(); + const int date = ar_header.mid(16, 12).trimmed().toInt(); + //const int uid = ar_header.mid( 28, 6 ).trimmed().toInt(); + //const int gid = ar_header.mid( 34, 6 ).trimmed().toInt(); + const int mode = ar_header.mid(40, 8).trimmed().toInt(nullptr, 8); + const qint64 size = ar_header.mid(48, 10).trimmed().toInt(); + if (size < 0) { + setErrorString(tr("Invalid size")); + return false; + } bool skip_entry = false; // Deal with special entries if (name.mid(0, 1) == "/") { if (name.mid(1, 1) == "/") { // Longfilename table entry - delete[] ar_longnames; - ar_longnames = new char[size + 1]; - ar_longnames[size] = '\0'; - dev->read(ar_longnames, size); + ar_longnames.resize(size); + // Read the table. Note that the QByteArray will contain NUL characters after each entry. + dev->read(ar_longnames.data(), size); skip_entry = true; - //qCDebug(KArchiveLog) << "Read in longnames entry"; + qCDebug(KArchiveLog) << "Read in longnames entry"; } else if (name.mid(1, 1) == " ") { // Symbol table entry - //qCDebug(KArchiveLog) << "Skipped symbol entry"; + qCDebug(KArchiveLog) << "Skipped symbol entry"; dev->seek(dev->pos() + size); skip_entry = true; - } else { // Longfilename - //qCDebug(KArchiveLog) << "Longfilename #" << name.mid(1, 15).toInt(); - if (! ar_longnames) { + } else { // Longfilename, look it up in the table + const int ar_longnamesIndex = name.mid(1, 15).trimmed().toInt(); + qCDebug(KArchiveLog) << "Longfilename #" << ar_longnamesIndex; + if (ar_longnames.isEmpty()) { setErrorString(tr("Invalid longfilename reference")); - delete[] ar_longnames; return false; } - name = &ar_longnames[name.mid(1, 15).toInt()]; - name = name.left(name.indexOf("/")); + if (ar_longnamesIndex < 0 || ar_longnamesIndex >= ar_longnames.size()) { + setErrorString(tr("Invalid longfilename position reference")); + return false; + } + name = QByteArray(ar_longnames.constData() + ar_longnamesIndex); + name.truncate(name.indexOf('/')); } } if (skip_entry) { continue; } - name = name.trimmed(); // Process filename + // Process filename + name = name.trimmed(); name.replace('/', QByteArray()); - //qCDebug(KArchiveLog) << "Filename: " << name << " Size: " << size; + qCDebug(KArchiveLog) << "Filename: " << name << " Size: " << size; KArchiveEntry *entry = new KArchiveFile(this, QString::fromLocal8Bit(name.constData()), mode, KArchivePrivate::time_tToDateTime(date), rootDir()->user(), rootDir()->group(), /*symlink*/ QString(), @@ -178,7 +183,6 @@ dev->seek(dev->pos() + size); // Skip contents } - delete[] ar_longnames; return true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/src/kcompressiondevice.cpp new/karchive-5.59.0/src/kcompressiondevice.cpp --- old/karchive-5.58.0/src/kcompressiondevice.cpp 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/src/kcompressiondevice.cpp 2019-06-01 18:36:00.000000000 +0200 @@ -18,6 +18,7 @@ */ #include "kcompressiondevice.h" +#include "kcompressiondevice_p.h" #include "loggingcategory.h" #include <config-compression.h> #include "kfilterbase.h" @@ -36,8 +37,6 @@ #include "kxzfilter.h" #endif -#define BUFFER_SIZE 8*1024 - #include <QDebug> class KCompressionDevicePrivate @@ -47,7 +46,6 @@ : bNeedHeader(true) , bSkipHeaders(false) , bOpenedUnderlyingDevice(false) - , bIgnoreData(false) , type(KCompressionDevice::None) , errorCode(QFileDevice::NoError) , deviceReadPos(0) @@ -60,7 +58,6 @@ bool bNeedHeader; bool bSkipHeaders; bool bOpenedUnderlyingDevice; - bool bIgnoreData; QByteArray buffer; // Used as 'input buffer' when reading, as 'output buffer' when writing QByteArray origFileName; KFilterBase::Result result; @@ -249,11 +246,16 @@ } //qCDebug(KArchiveLog) << "reading " << bytesToRead << " dummy bytes"; - QByteArray dummy(qMin(bytesToRead, qint64(3 * BUFFER_SIZE)), 0); - d->bIgnoreData = true; - const bool result = (read(dummy.data(), bytesToRead) == bytesToRead); - d->bIgnoreData = false; - return result; + QByteArray dummy(qMin(bytesToRead, qint64(SEEK_BUFFER_SIZE)), 0); + while (bytesToRead > 0) { + const qint64 bytesToReadThisTime = qMin(bytesToRead, qint64(dummy.size())); + const bool result = (read(dummy.data(), bytesToReadThisTime) == bytesToReadThisTime); + if (!result) { + return false; + } + bytesToRead -= bytesToReadThisTime; + } + return true; } bool KCompressionDevice::atEnd() const @@ -281,15 +283,8 @@ return -1; } - qint64 outBufferSize; - if (d->bIgnoreData) { - outBufferSize = qMin(maxlen, static_cast<qint64>(3 * BUFFER_SIZE)); - } else { - outBufferSize = maxlen; - } - outBufferSize -= dataReceived; - qint64 availOut = outBufferSize; - filter->setOutBuffer(data, outBufferSize); + qint64 availOut = maxlen; + filter->setOutBuffer(data, maxlen); while (dataReceived < maxlen) { if (filter->inBufferEmpty()) { @@ -327,12 +322,8 @@ } dataReceived += outReceived; - if (!d->bIgnoreData) { // Move on in the output buffer - data += outReceived; - availOut = maxlen - dataReceived; - } else if (maxlen - dataReceived < outBufferSize) { - availOut = maxlen - dataReceived; - } + data += outReceived; + availOut = maxlen - dataReceived; if (d->result == KFilterBase::End) { // We're actually at the end, no more data to check if (filter->device()->atEnd()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/src/kcompressiondevice_p.h new/karchive-5.59.0/src/kcompressiondevice_p.h --- old/karchive-5.58.0/src/kcompressiondevice_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/karchive-5.59.0/src/kcompressiondevice_p.h 2019-06-01 18:36:00.000000000 +0200 @@ -0,0 +1,25 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <fa...@kde.org> + Copyright (C) 2011 Mario Bensi <mbe...@ipsquad.net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef __kcompressiondevice_p_h +#define __kcompressiondevice_p_h + +#define BUFFER_SIZE 8*1024 +#define SEEK_BUFFER_SIZE 3*BUFFER_SIZE + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/src/ktar.cpp new/karchive-5.59.0/src/ktar.cpp --- old/karchive-5.58.0/src/ktar.cpp 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/src/ktar.cpp 2019-06-01 18:36:00.000000000 +0200 @@ -238,7 +238,7 @@ qint64 size = QByteArray(buffer + 0x7c, 12).trimmed().toLongLong(nullptr, 8 /*octal*/); size--; // ignore trailing null - if (size > std::numeric_limits<int>::max()) { + if (size > std::numeric_limits<int>::max() - 32) { // QByteArray can't really be INT_MAX big, it's max size is something between INT_MAX - 32 and INT_MAX depending the platform so just be safe qCWarning(KArchiveLog) << "Failed to allocate memory for longlink of size" << size; return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/tests/CMakeLists.txt new/karchive-5.59.0/tests/CMakeLists.txt --- old/karchive-5.58.0/tests/CMakeLists.txt 2019-05-05 00:41:47.000000000 +0200 +++ new/karchive-5.59.0/tests/CMakeLists.txt 2019-06-01 18:36:00.000000000 +0200 @@ -11,6 +11,7 @@ endmacro(KARCHIVE_EXECUTABLE_TESTS) karchive_executable_tests( + kartest ktartest krcctest kziptest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/karchive-5.58.0/tests/kartest.cpp new/karchive-5.59.0/tests/kartest.cpp --- old/karchive-5.58.0/tests/kartest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/karchive-5.59.0/tests/kartest.cpp 2019-06-01 18:36:00.000000000 +0200 @@ -0,0 +1,71 @@ +/* This file is part of the KDE project + Copyright (C) 2002-2019 David Faure <fa...@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kar.h" +#include <stdio.h> +#include <QDebug> + +void recursive_print(const KArchiveDirectory *dir, const QString &path) +{ + QStringList l = dir->entries(); + l.sort(); + QStringList::ConstIterator it = l.constBegin(); + for (; it != l.constEnd(); ++it) { + const KArchiveEntry *entry = dir->entry((*it)); + printf("mode=%7o path=%s type=%s size=%lld\n", entry->permissions(), qPrintable(path + (*it)), + entry->isFile() ? "file" : "dir", + entry->isFile() ? static_cast<const KArchiveFile *>(entry)->size() : 0); + if (!entry->symLinkTarget().isEmpty()) { + printf(" (symlink to %s)\n", qPrintable(entry->symLinkTarget())); + } + if (entry->isDirectory()) { + recursive_print((KArchiveDirectory *)entry, path + (*it) + '/'); + } + } +} + +// See karchivetest.cpp for the unittest that covers KAr. + +int main(int argc, char **argv) +{ + if (argc != 2) { + printf("\n" + " Usage :\n" + " ./kartest /path/to/existing_file.a tests listing an existing archive\n"); + return 1; + } + + KAr archive(argv[1]); + + if (!archive.open(QIODevice::ReadOnly)) { + printf("Could not open %s for reading\n", argv[1]); + return 1; + } + + const KArchiveDirectory *dir = archive.directory(); + + //printf("calling recursive_print\n"); + recursive_print(dir, QLatin1String("")); + //printf("recursive_print called\n"); + + archive.close(); + + return 0; +} +