KArchive

kar.cpp
1 /* This file is part of the KDE libraries
2  SPDX-FileCopyrightText: 2002 Laurence Anderson <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "kar.h"
8 #include "karchive_p.h"
9 #include "loggingcategory.h"
10 
11 #include <QDebug>
12 #include <QFile>
13 
14 #include <limits>
15 
16 #include "kcompressiondevice.h"
17 //#include "klimitediodevice_p.h"
18 
19 // As documented in QByteArray
20 static constexpr int kMaxQByteArraySize = std::numeric_limits<int>::max() - 32;
21 
22 ////////////////////////////////////////////////////////////////////////
23 /////////////////////////// KAr ///////////////////////////////////////
24 ////////////////////////////////////////////////////////////////////////
25 
26 class Q_DECL_HIDDEN KAr::KArPrivate
27 {
28 public:
29  KArPrivate()
30  {
31  }
32 };
33 
34 KAr::KAr(const QString &filename)
35  : KArchive(filename)
36  , d(new KArPrivate)
37 {
38 }
39 
41  : KArchive(dev)
42  , d(new KArPrivate)
43 {
44 }
45 
47 {
48  if (isOpen()) {
49  close();
50  }
51  delete d;
52 }
53 
54 bool KAr::doPrepareWriting(const QString &, const QString &, const QString &, qint64, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
55 {
56  setErrorString(tr("Cannot write to AR file"));
57  qCWarning(KArchiveLog) << "doPrepareWriting not implemented for KAr";
58  return false;
59 }
60 
62 {
63  setErrorString(tr("Cannot write to AR file"));
64  qCWarning(KArchiveLog) << "doFinishWriting not implemented for KAr";
65  return false;
66 }
67 
68 bool KAr::doWriteDir(const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
69 {
70  setErrorString(tr("Cannot write to AR file"));
71  qCWarning(KArchiveLog) << "doWriteDir not implemented for KAr";
72  return false;
73 }
74 
75 bool KAr::doWriteSymLink(const QString &, const QString &, const QString &, const QString &, mode_t, const QDateTime &, const QDateTime &, const QDateTime &)
76 {
77  setErrorString(tr("Cannot write to AR file"));
78  qCWarning(KArchiveLog) << "doWriteSymLink not implemented for KAr";
79  return false;
80 }
81 
83 {
84  // Open archive
85 
86  if (mode == QIODevice::WriteOnly) {
87  return true;
88  }
90  setErrorString(tr("Unsupported mode %1").arg(mode));
91  return false;
92  }
93 
94  QIODevice *dev = device();
95  if (!dev) {
96  return false;
97  }
98 
99  QByteArray magic = dev->read(7);
100  if (magic != "!<arch>") {
101  setErrorString(tr("Invalid main magic"));
102  return false;
103  }
104 
105  QByteArray ar_longnames;
106  while (!dev->atEnd()) {
107  QByteArray ar_header;
108  ar_header.resize(60);
109 
110  dev->seek(dev->pos() + (2 - (dev->pos() % 2)) % 2); // Ar headers are padded to byte boundary
111 
112  if (dev->read(ar_header.data(), 60) != 60) { // Read ar header
113  qCWarning(KArchiveLog) << "Couldn't read header";
114  return true; // Probably EOF / trailing junk
115  }
116 
117  if (!ar_header.endsWith("`\n")) { // Check header magic // krazy:exclude=strings
118  setErrorString(tr("Invalid magic"));
119  return false;
120  }
121 
122  QByteArray name = ar_header.mid(0, 16); // Process header
123  const int date = ar_header.mid(16, 12).trimmed().toInt();
124  // const int uid = ar_header.mid( 28, 6 ).trimmed().toInt();
125  // const int gid = ar_header.mid( 34, 6 ).trimmed().toInt();
126  const int mode = ar_header.mid(40, 8).trimmed().toInt(nullptr, 8);
127  const qint64 size = ar_header.mid(48, 10).trimmed().toInt();
128  if (size < 0 || size > kMaxQByteArraySize) {
129  setErrorString(tr("Invalid size"));
130  return false;
131  }
132 
133  bool skip_entry = false; // Deal with special entries
134  if (name.mid(0, 1) == "/") {
135  if (name.mid(1, 1) == "/") { // Longfilename table entry
136  ar_longnames.resize(size);
137  // Read the table. Note that the QByteArray will contain NUL characters after each entry.
138  dev->read(ar_longnames.data(), size);
139  skip_entry = true;
140  qCDebug(KArchiveLog) << "Read in longnames entry";
141  } else if (name.mid(1, 1) == " ") { // Symbol table entry
142  qCDebug(KArchiveLog) << "Skipped symbol entry";
143  dev->seek(dev->pos() + size);
144  skip_entry = true;
145  } else { // Longfilename, look it up in the table
146  const int ar_longnamesIndex = name.mid(1, 15).trimmed().toInt();
147  qCDebug(KArchiveLog) << "Longfilename #" << ar_longnamesIndex;
148  if (ar_longnames.isEmpty()) {
149  setErrorString(tr("Invalid longfilename reference"));
150  return false;
151  }
152  if (ar_longnamesIndex < 0 || ar_longnamesIndex >= ar_longnames.size()) {
153  setErrorString(tr("Invalid longfilename position reference"));
154  return false;
155  }
156  name = QByteArray(ar_longnames.constData() + ar_longnamesIndex);
157  name.truncate(name.indexOf('/'));
158  }
159  }
160  if (skip_entry) {
161  continue;
162  }
163 
164  // Process filename
165  name = name.trimmed();
166  name.replace('/', QByteArray());
167  qCDebug(KArchiveLog) << "Filename: " << name << " Size: " << size;
168 
169  KArchiveEntry *entry = new KArchiveFile(this,
170  QString::fromLocal8Bit(name.constData()),
171  mode,
172  KArchivePrivate::time_tToDateTime(date),
173  rootDir()->user(),
174  rootDir()->group(),
175  /*symlink*/ QString(),
176  dev->pos(),
177  size);
178  rootDir()->addEntry(entry); // Ar files don't support directories, so everything in root
179 
180  dev->seek(dev->pos() + size); // Skip contents
181  }
182 
183  return true;
184 }
185 
187 {
188  // Close the archive
189  return true;
190 }
191 
192 void KAr::virtual_hook(int id, void *data)
193 {
194  KArchive::virtual_hook(id, data);
195 }
typedef OpenMode
bool doWriteDir(const QString &name, const QString &user, const QString &group, mode_t perm, const QDateTime &atime, const QDateTime &mtime, const QDateTime &ctime) override
Write a directory to the archive.
Definition: kar.cpp:68
QIODevice * device() const
The underlying device.
Definition: karchive.cpp:618
~KAr() override
If the ar file is still opened, then it will be closed automatically by the destructor.
Definition: kar.cpp:46
QByteArray trimmed() const const
virtual bool seek(qint64 pos)
KAr(const QString &filename)
Creates an instance that operates on the given filename.
Definition: kar.cpp:34
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
Definition: karchive.cpp:509
A class for reading ar archives.
Definition: kar.h:20
virtual bool close()
Closes the archive.
Definition: karchive.cpp:214
Base class for the archive-file's directory structure.
Definition: karchiveentry.h:34
QString fromLocal8Bit(const char *str, int size)
virtual qint64 pos() const const
QByteArray mid(int pos, int len) const const
bool doWriteSymLink(const QString &name, const QString &target, const QString &user, const QString &group, mode_t perm, const QDateTime &atime, const QDateTime &mtime, const QDateTime &ctime) override
Writes a symbolic link to the archive.
Definition: kar.cpp:75
generic class for reading/writing archives
Definition: karchive.h:39
bool isOpen() const
Checks whether the archive is open.
Definition: karchive.cpp:623
QIODevice::OpenMode mode() const
Returns the mode in which the archive was opened.
Definition: karchive.cpp:613
bool doPrepareWriting(const QString &name, const QString &user, const QString &group, qint64 size, mode_t perm, const QDateTime &atime, const QDateTime &mtime, const QDateTime &ctime) override
This virtual method must be implemented by subclasses.
Definition: kar.cpp:54
qint64 read(char *data, qint64 maxSize)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
void resize(int size)
void addEntry(KArchiveEntry *)
Definition: karchive.cpp:912
const char * constData() const const
void setErrorString(const QString &errorStr)
Sets error description.
Definition: karchive.cpp:474
A file in an archive.
Definition: karchivefile.h:24
virtual bool atEnd() const const
bool endsWith(const QByteArray &ba) const const
bool doFinishWriting(qint64 size) override
Called after writing the data.
Definition: kar.cpp:61
int size() const const
bool closeArchive() override
Closes the archive.
Definition: kar.cpp:186
bool openArchive(QIODevice::OpenMode mode) override
Opens the archive for reading.
Definition: kar.cpp:82
char * data()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 12 2022 04:03:10 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.