1 | /* This file is part of the KDE libraries |
2 | SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org> |
3 | SPDX-FileCopyrightText: 2003 Leo Savernik <l.savernik@aon.at> |
4 | |
5 | Moved from ktar.h by Roberto Teixeira <maragato@kde.org> |
6 | |
7 | SPDX-License-Identifier: LGPL-2.0-or-later |
8 | */ |
9 | #ifndef KARCHIVE_H |
10 | #define KARCHIVE_H |
11 | |
12 | #include <sys/stat.h> |
13 | #include <sys/types.h> |
14 | |
15 | #include <QByteArrayView> |
16 | #include <QCoreApplication> |
17 | #include <QDate> |
18 | #include <QHash> |
19 | #include <QIODevice> |
20 | #include <QString> |
21 | #include <QStringList> |
22 | |
23 | #include <karchive_export.h> |
24 | |
25 | #ifdef Q_OS_WIN |
26 | #include <qplatformdefs.h> // mode_t |
27 | #endif |
28 | |
29 | class KArchiveDirectory; |
30 | class KArchiveFile; |
31 | |
32 | class KArchivePrivate; |
33 | /** |
34 | * @class KArchive karchive.h KArchive |
35 | * |
36 | * KArchive is a base class for reading and writing archives. |
37 | * @short generic class for reading/writing archives |
38 | * @author David Faure <faure@kde.org> |
39 | */ |
40 | class KARCHIVE_EXPORT KArchive |
41 | { |
42 | Q_DECLARE_TR_FUNCTIONS(KArchive) |
43 | |
44 | protected: |
45 | /** |
46 | * Base constructor (protected since this is a pure virtual class). |
47 | * @param fileName is a local path (e.g. "/tmp/myfile.ext"), |
48 | * from which the archive will be read from, or into which the archive |
49 | * will be written, depending on the mode given to open(). |
50 | */ |
51 | explicit KArchive(const QString &fileName); |
52 | |
53 | /** |
54 | * Base constructor (protected since this is a pure virtual class). |
55 | * @param dev the I/O device where the archive reads its data |
56 | * Note that this can be a file, but also a data buffer, a compression filter, etc. |
57 | * For a file in writing mode it is better to use the other constructor |
58 | * though, to benefit from the use of QSaveFile when saving. |
59 | */ |
60 | explicit KArchive(QIODevice *dev); |
61 | |
62 | public: |
63 | virtual ~KArchive(); |
64 | |
65 | /** |
66 | * Opens the archive for reading or writing. |
67 | * Inherited classes might want to reimplement openArchive instead. |
68 | * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly |
69 | * @see close |
70 | */ |
71 | virtual bool open(QIODevice::OpenMode mode); |
72 | |
73 | /** |
74 | * Closes the archive. |
75 | * Inherited classes might want to reimplement closeArchive instead. |
76 | * |
77 | * @return true if close succeeded without problems |
78 | * @see open |
79 | */ |
80 | virtual bool close(); |
81 | |
82 | /** |
83 | * Returns a description of the last error |
84 | * @since 5.29 |
85 | */ |
86 | QString errorString() const; |
87 | |
88 | /** |
89 | * Checks whether the archive is open. |
90 | * @return true if the archive is opened |
91 | */ |
92 | bool isOpen() const; |
93 | |
94 | /** |
95 | * Returns the mode in which the archive was opened |
96 | * @return the mode in which the archive was opened (QIODevice::ReadOnly or QIODevice::WriteOnly) |
97 | * @see open() |
98 | */ |
99 | QIODevice::OpenMode mode() const; |
100 | |
101 | /** |
102 | * The underlying device. |
103 | * @return the underlying device. |
104 | */ |
105 | QIODevice *device() const; |
106 | |
107 | /** |
108 | * The name of the archive file, as passed to the constructor that takes a |
109 | * fileName, or an empty string if you used the QIODevice constructor. |
110 | * @return the name of the file, or QString() if unknown |
111 | */ |
112 | QString fileName() const; |
113 | |
114 | /** |
115 | * If an archive is opened for reading, then the contents |
116 | * of the archive can be accessed via this function. |
117 | * @return the directory of the archive |
118 | */ |
119 | const KArchiveDirectory *directory() const; |
120 | |
121 | /** |
122 | * Writes a local file into the archive. The main difference with writeFile, |
123 | * is that this method minimizes memory usage, by not loading the whole file |
124 | * into memory in one go. |
125 | * |
126 | * If @p fileName is a symbolic link, it will be written as is, i.e. |
127 | * it will not be resolved before. |
128 | * @param fileName full path to an existing local file, to be added to the archive. |
129 | * @param destName the resulting name (or relative path) of the file in the archive. |
130 | */ |
131 | bool addLocalFile(const QString &fileName, const QString &destName); |
132 | |
133 | /** |
134 | * Writes a local directory into the archive, including all its contents, recursively. |
135 | * Calls addLocalFile for each file to be added. |
136 | * |
137 | * It will also add a @p path that is a symbolic link to a |
138 | * directory. The symbolic link will be dereferenced and the content of the |
139 | * directory it is pointing to added recursively. However, symbolic links |
140 | * *under* @p path will be stored as is. |
141 | * @param path full path to an existing local directory, to be added to the archive. |
142 | * @param destName the resulting name (or relative path) of the file in the archive. |
143 | */ |
144 | bool addLocalDirectory(const QString &path, const QString &destName); |
145 | |
146 | /** |
147 | * If an archive is opened for writing then you can add new directories |
148 | * using this function. KArchive won't write one directory twice. |
149 | * |
150 | * This method also allows some file metadata to be set. |
151 | * However, depending on the archive type not all metadata might be regarded. |
152 | * |
153 | * @param name the name of the directory |
154 | * @param user the user that owns the directory |
155 | * @param group the group that owns the directory |
156 | * @param perm permissions of the directory |
157 | * @param atime time the file was last accessed |
158 | * @param mtime modification time of the file |
159 | * @param ctime time of last status change |
160 | */ |
161 | bool writeDir(const QString &name, |
162 | const QString &user = QString(), |
163 | const QString &group = QString(), |
164 | mode_t perm = 040755, |
165 | const QDateTime &atime = QDateTime(), |
166 | const QDateTime &mtime = QDateTime(), |
167 | const QDateTime &ctime = QDateTime()); |
168 | |
169 | /** |
170 | * Writes a symbolic link to the archive if supported. |
171 | * The archive must be opened for writing. |
172 | * |
173 | * @param name name of symbolic link |
174 | * @param target target of symbolic link |
175 | * @param user the user that owns the directory |
176 | * @param group the group that owns the directory |
177 | * @param perm permissions of the directory |
178 | * @param atime time the file was last accessed |
179 | * @param mtime modification time of the file |
180 | * @param ctime time of last status change |
181 | */ |
182 | bool writeSymLink(const QString &name, |
183 | const QString &target, |
184 | const QString &user = QString(), |
185 | const QString &group = QString(), |
186 | mode_t perm = 0120755, |
187 | const QDateTime &atime = QDateTime(), |
188 | const QDateTime &mtime = QDateTime(), |
189 | const QDateTime &ctime = QDateTime()); |
190 | |
191 | /** |
192 | * Writes a new file into the archive. |
193 | * |
194 | * The archive must be opened for writing first. |
195 | * |
196 | * The necessary parent directories are created automatically |
197 | * if needed. For instance, writing "mydir/test1" does not |
198 | * require creating the directory "mydir" first. |
199 | * |
200 | * This method also allows some file metadata to be |
201 | * set. However, depending on the archive type not all metadata might be |
202 | * written out. |
203 | * |
204 | * @param name the name of the file |
205 | * @param data the data to write |
206 | * @param perm permissions of the file |
207 | * @param user the user that owns the file |
208 | * @param group the group that owns the file |
209 | * @param atime time the file was last accessed |
210 | * @param mtime modification time of the file |
211 | * @param ctime time of last status change |
212 | * @since 6.0 |
213 | */ |
214 | bool writeFile(const QString &name, |
215 | QByteArrayView data, |
216 | mode_t perm = 0100644, |
217 | const QString &user = QString(), |
218 | const QString &group = QString(), |
219 | const QDateTime &atime = QDateTime(), |
220 | const QDateTime &mtime = QDateTime(), |
221 | const QDateTime &ctime = QDateTime()); |
222 | |
223 | /** |
224 | * Here's another way of writing a file into an archive: |
225 | * Call prepareWriting(), then call writeData() |
226 | * as many times as wanted then call finishWriting( totalSize ). |
227 | * For tar.gz files, you need to know the size before hand, it is needed in the header! |
228 | * For zip files, size isn't used. |
229 | * |
230 | * This method also allows some file metadata to be |
231 | * set. However, depending on the archive type not all metadata might be |
232 | * regarded. |
233 | * @param name the name of the file |
234 | * @param user the user that owns the file |
235 | * @param group the group that owns the file |
236 | * @param size the size of the file |
237 | * @param perm permissions of the file |
238 | * @param atime time the file was last accessed |
239 | * @param mtime modification time of the file |
240 | * @param ctime time of last status change |
241 | */ |
242 | bool prepareWriting(const QString &name, |
243 | const QString &user, |
244 | const QString &group, |
245 | qint64 size, |
246 | mode_t perm = 0100644, |
247 | const QDateTime &atime = QDateTime(), |
248 | const QDateTime &mtime = QDateTime(), |
249 | const QDateTime &ctime = QDateTime()); |
250 | |
251 | /** |
252 | * Write data into the current file - to be called after calling prepareWriting |
253 | * @param data a pointer to the data |
254 | * @param size the size of the chunk |
255 | * @return @c true if successful, @c false otherwise |
256 | */ |
257 | bool writeData(const char *data, qint64 size); |
258 | |
259 | /** |
260 | * Overload for writeData(const char *, qint64); |
261 | * @since 6.0 |
262 | */ |
263 | bool writeData(QByteArrayView data); |
264 | |
265 | /** |
266 | * Call finishWriting after writing the data. |
267 | * @param size the size of the file |
268 | * @see prepareWriting() |
269 | */ |
270 | bool finishWriting(qint64 size); |
271 | |
272 | protected: |
273 | /** |
274 | * Opens an archive for reading or writing. |
275 | * Called by open. |
276 | * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly |
277 | */ |
278 | virtual bool openArchive(QIODevice::OpenMode mode) = 0; |
279 | |
280 | /** |
281 | * Closes the archive. |
282 | * Called by close. |
283 | */ |
284 | virtual bool closeArchive() = 0; |
285 | |
286 | /** |
287 | * Sets error description |
288 | * @param errorStr error description |
289 | * @since 5.29 |
290 | */ |
291 | void setErrorString(const QString &errorStr); |
292 | |
293 | /** |
294 | * Retrieves or create the root directory. |
295 | * The default implementation assumes that openArchive() did the parsing, |
296 | * so it creates a dummy rootdir if none was set (write mode, or no '/' in the archive). |
297 | * Reimplement this to provide parsing/listing on demand. |
298 | * @return the root directory |
299 | */ |
300 | virtual KArchiveDirectory *rootDir(); |
301 | |
302 | /** |
303 | * Write a directory to the archive. |
304 | * This virtual method must be implemented by subclasses. |
305 | * |
306 | * Depending on the archive type not all metadata might be used. |
307 | * |
308 | * @param name the name of the directory |
309 | * @param user the user that owns the directory |
310 | * @param group the group that owns the directory |
311 | * @param perm permissions of the directory. Use 040755 if you don't have any other information. |
312 | * @param atime time the file was last accessed |
313 | * @param mtime modification time of the file |
314 | * @param ctime time of last status change |
315 | * @see writeDir |
316 | */ |
317 | virtual bool doWriteDir(const QString &name, |
318 | const QString &user, |
319 | const QString &group, |
320 | mode_t perm, |
321 | const QDateTime &atime, |
322 | const QDateTime &mtime, |
323 | const QDateTime &ctime) = 0; |
324 | |
325 | /** |
326 | * Writes a symbolic link to the archive. |
327 | * This virtual method must be implemented by subclasses. |
328 | * |
329 | * @param name name of symbolic link |
330 | * @param target target of symbolic link |
331 | * @param user the user that owns the directory |
332 | * @param group the group that owns the directory |
333 | * @param perm permissions of the directory |
334 | * @param atime time the file was last accessed |
335 | * @param mtime modification time of the file |
336 | * @param ctime time of last status change |
337 | * @see writeSymLink |
338 | */ |
339 | virtual bool doWriteSymLink(const QString &name, |
340 | const QString &target, |
341 | const QString &user, |
342 | const QString &group, |
343 | mode_t perm, |
344 | const QDateTime &atime, |
345 | const QDateTime &mtime, |
346 | const QDateTime &ctime) = 0; |
347 | |
348 | /** |
349 | * This virtual method must be implemented by subclasses. |
350 | * |
351 | * Depending on the archive type not all metadata might be used. |
352 | * |
353 | * @param name the name of the file |
354 | * @param user the user that owns the file |
355 | * @param group the group that owns the file |
356 | * @param size the size of the file |
357 | * @param perm permissions of the file. Use 0100644 if you don't have any more specific permissions to set. |
358 | * @param atime time the file was last accessed |
359 | * @param mtime modification time of the file |
360 | * @param ctime time of last status change |
361 | * @see prepareWriting |
362 | */ |
363 | virtual bool doPrepareWriting(const QString &name, |
364 | const QString &user, |
365 | const QString &group, |
366 | qint64 size, |
367 | mode_t perm, |
368 | const QDateTime &atime, |
369 | const QDateTime &mtime, |
370 | const QDateTime &ctime) = 0; |
371 | |
372 | /** |
373 | * Write data into the current file. |
374 | * Called by writeData. |
375 | * |
376 | * @param data a pointer to the data |
377 | * @param size the size of the chunk |
378 | * @return @c true if successful, @c false otherwise |
379 | * @see writeData |
380 | * @since 6.0 |
381 | */ |
382 | virtual bool doWriteData(const char *data, qint64 size); |
383 | |
384 | /** |
385 | * Called after writing the data. |
386 | * This virtual method must be implemented by subclasses. |
387 | * |
388 | * @param size the size of the file |
389 | * @see finishWriting() |
390 | */ |
391 | virtual bool doFinishWriting(qint64 size) = 0; |
392 | |
393 | /** |
394 | * Ensures that @p path exists, create otherwise. |
395 | * This handles e.g. tar files missing directory entries, like mico-2.3.0.tar.gz :) |
396 | * @param path the path of the directory |
397 | * @return the directory with the given @p path |
398 | */ |
399 | KArchiveDirectory *findOrCreate(const QString &path); |
400 | |
401 | /** |
402 | * Can be reimplemented in order to change the creation of the device |
403 | * (when using the fileName constructor). By default this method uses |
404 | * QSaveFile when saving, and a simple QFile on reading. |
405 | * This method is called by open(). |
406 | */ |
407 | virtual bool createDevice(QIODevice::OpenMode mode); |
408 | |
409 | /** |
410 | * Can be called by derived classes in order to set the underlying device. |
411 | * Note that KArchive will -not- own the device, it must be deleted by the derived class. |
412 | */ |
413 | void setDevice(QIODevice *dev); |
414 | |
415 | /** |
416 | * Derived classes call setRootDir from openArchive, |
417 | * to set the root directory after parsing an existing archive. |
418 | */ |
419 | void setRootDir(KArchiveDirectory *rootDir); |
420 | |
421 | protected: |
422 | virtual void virtual_hook(int id, void *data); |
423 | |
424 | private: |
425 | friend class KArchivePrivate; |
426 | KArchivePrivate *const d; |
427 | }; |
428 | |
429 | // for source compat |
430 | #include "karchivedirectory.h" |
431 | #include "karchivefile.h" |
432 | |
433 | #endif |
434 | |