File indexing completed on 2024-04-21 03:52:31

0001 /* This file is part of the KDE libraries
0002    SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org>
0003    SPDX-FileCopyrightText: 2003 Leo Savernik <l.savernik@aon.at>
0004 
0005    Moved from ktar.h by Roberto Teixeira <maragato@kde.org>
0006 
0007    SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 #ifndef KARCHIVE_H
0010 #define KARCHIVE_H
0011 
0012 #include <sys/stat.h>
0013 #include <sys/types.h>
0014 
0015 #include <QByteArrayView>
0016 #include <QCoreApplication>
0017 #include <QDate>
0018 #include <QHash>
0019 #include <QIODevice>
0020 #include <QString>
0021 #include <QStringList>
0022 
0023 #include <karchive_export.h>
0024 
0025 #ifdef Q_OS_WIN
0026 #include <qplatformdefs.h> // mode_t
0027 #endif
0028 
0029 class KArchiveDirectory;
0030 class KArchiveFile;
0031 
0032 class KArchivePrivate;
0033 /**
0034  * @class KArchive karchive.h KArchive
0035  *
0036  * KArchive is a base class for reading and writing archives.
0037  * @short generic class for reading/writing archives
0038  * @author David Faure <faure@kde.org>
0039  */
0040 class KARCHIVE_EXPORT KArchive
0041 {
0042     Q_DECLARE_TR_FUNCTIONS(KArchive)
0043 
0044 protected:
0045     /**
0046      * Base constructor (protected since this is a pure virtual class).
0047      * @param fileName is a local path (e.g. "/tmp/myfile.ext"),
0048      * from which the archive will be read from, or into which the archive
0049      * will be written, depending on the mode given to open().
0050      */
0051     explicit KArchive(const QString &fileName);
0052 
0053     /**
0054      * Base constructor (protected since this is a pure virtual class).
0055      * @param dev the I/O device where the archive reads its data
0056      * Note that this can be a file, but also a data buffer, a compression filter, etc.
0057      * For a file in writing mode it is better to use the other constructor
0058      * though, to benefit from the use of QSaveFile when saving.
0059      */
0060     explicit KArchive(QIODevice *dev);
0061 
0062 public:
0063     virtual ~KArchive();
0064 
0065     /**
0066      * Opens the archive for reading or writing.
0067      * Inherited classes might want to reimplement openArchive instead.
0068      * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly
0069      * @see close
0070      */
0071     virtual bool open(QIODevice::OpenMode mode);
0072 
0073     /**
0074      * Closes the archive.
0075      * Inherited classes might want to reimplement closeArchive instead.
0076      *
0077      * @return true if close succeeded without problems
0078      * @see open
0079      */
0080     virtual bool close();
0081 
0082     /**
0083      * Returns a description of the last error
0084      * @since 5.29
0085      */
0086     QString errorString() const;
0087 
0088     /**
0089      * Checks whether the archive is open.
0090      * @return true if the archive is opened
0091      */
0092     bool isOpen() const;
0093 
0094     /**
0095      * Returns the mode in which the archive was opened
0096      * @return the mode in which the archive was opened (QIODevice::ReadOnly or QIODevice::WriteOnly)
0097      * @see open()
0098      */
0099     QIODevice::OpenMode mode() const;
0100 
0101     /**
0102      * The underlying device.
0103      * @return the underlying device.
0104      */
0105     QIODevice *device() const;
0106 
0107     /**
0108      * The name of the archive file, as passed to the constructor that takes a
0109      * fileName, or an empty string if you used the QIODevice constructor.
0110      * @return the name of the file, or QString() if unknown
0111      */
0112     QString fileName() const;
0113 
0114     /**
0115      * If an archive is opened for reading, then the contents
0116      * of the archive can be accessed via this function.
0117      * @return the directory of the archive
0118      */
0119     const KArchiveDirectory *directory() const;
0120 
0121     /**
0122      * Writes a local file into the archive. The main difference with writeFile,
0123      * is that this method minimizes memory usage, by not loading the whole file
0124      * into memory in one go.
0125      *
0126      * If @p fileName is a symbolic link, it will be written as is, i.e.
0127      * it will not be resolved before.
0128      * @param fileName full path to an existing local file, to be added to the archive.
0129      * @param destName the resulting name (or relative path) of the file in the archive.
0130      */
0131     bool addLocalFile(const QString &fileName, const QString &destName);
0132 
0133     /**
0134      * Writes a local directory into the archive, including all its contents, recursively.
0135      * Calls addLocalFile for each file to be added.
0136      *
0137      * It will also add a @p path that is a symbolic link to a
0138      * directory. The symbolic link will be dereferenced and the content of the
0139      * directory it is pointing to added recursively. However, symbolic links
0140      * *under* @p path will be stored as is.
0141      * @param path full path to an existing local directory, to be added to the archive.
0142      * @param destName the resulting name (or relative path) of the file in the archive.
0143      */
0144     bool addLocalDirectory(const QString &path, const QString &destName);
0145 
0146     /**
0147      * If an archive is opened for writing then you can add new directories
0148      * using this function. KArchive won't write one directory twice.
0149      *
0150      * This method also allows some file metadata to be set.
0151      * However, depending on the archive type not all metadata might be regarded.
0152      *
0153      * @param name the name of the directory
0154      * @param user the user that owns the directory
0155      * @param group the group that owns the directory
0156      * @param perm permissions of the directory
0157      * @param atime time the file was last accessed
0158      * @param mtime modification time of the file
0159      * @param ctime time of last status change
0160      */
0161     bool writeDir(const QString &name,
0162                   const QString &user = QString(),
0163                   const QString &group = QString(),
0164                   mode_t perm = 040755,
0165                   const QDateTime &atime = QDateTime(),
0166                   const QDateTime &mtime = QDateTime(),
0167                   const QDateTime &ctime = QDateTime());
0168 
0169     /**
0170      * Writes a symbolic link to the archive if supported.
0171      * The archive must be opened for writing.
0172      *
0173      * @param name name of symbolic link
0174      * @param target target of symbolic link
0175      * @param user the user that owns the directory
0176      * @param group the group that owns the directory
0177      * @param perm permissions of the directory
0178      * @param atime time the file was last accessed
0179      * @param mtime modification time of the file
0180      * @param ctime time of last status change
0181      */
0182     bool writeSymLink(const QString &name,
0183                       const QString &target,
0184                       const QString &user = QString(),
0185                       const QString &group = QString(),
0186                       mode_t perm = 0120755,
0187                       const QDateTime &atime = QDateTime(),
0188                       const QDateTime &mtime = QDateTime(),
0189                       const QDateTime &ctime = QDateTime());
0190 
0191     /**
0192      * Writes a new file into the archive.
0193      *
0194      * The archive must be opened for writing first.
0195      *
0196      * The necessary parent directories are created automatically
0197      * if needed. For instance, writing "mydir/test1" does not
0198      * require creating the directory "mydir" first.
0199      *
0200      * This method also allows some file metadata to be
0201      * set. However, depending on the archive type not all metadata might be
0202      * written out.
0203      *
0204      * @param name the name of the file
0205      * @param data the data to write
0206      * @param perm permissions of the file
0207      * @param user the user that owns the file
0208      * @param group the group that owns the file
0209      * @param atime time the file was last accessed
0210      * @param mtime modification time of the file
0211      * @param ctime time of last status change
0212      * @since 6.0
0213      */
0214     bool writeFile(const QString &name,
0215                    QByteArrayView data,
0216                    mode_t perm = 0100644,
0217                    const QString &user = QString(),
0218                    const QString &group = QString(),
0219                    const QDateTime &atime = QDateTime(),
0220                    const QDateTime &mtime = QDateTime(),
0221                    const QDateTime &ctime = QDateTime());
0222 
0223     /**
0224      * Here's another way of writing a file into an archive:
0225      * Call prepareWriting(), then call writeData()
0226      * as many times as wanted then call finishWriting( totalSize ).
0227      * For tar.gz files, you need to know the size before hand, it is needed in the header!
0228      * For zip files, size isn't used.
0229      *
0230      * This method also allows some file metadata to be
0231      * set. However, depending on the archive type not all metadata might be
0232      * regarded.
0233      * @param name the name of the file
0234      * @param user the user that owns the file
0235      * @param group the group that owns the file
0236      * @param size the size of the file
0237      * @param perm permissions of the file
0238      * @param atime time the file was last accessed
0239      * @param mtime modification time of the file
0240      * @param ctime time of last status change
0241      */
0242     bool prepareWriting(const QString &name,
0243                         const QString &user,
0244                         const QString &group,
0245                         qint64 size,
0246                         mode_t perm = 0100644,
0247                         const QDateTime &atime = QDateTime(),
0248                         const QDateTime &mtime = QDateTime(),
0249                         const QDateTime &ctime = QDateTime());
0250 
0251     /**
0252      * Write data into the current file - to be called after calling prepareWriting
0253      * @param data a pointer to the data
0254      * @param size the size of the chunk
0255      * @return @c true if successful, @c false otherwise
0256      */
0257     bool writeData(const char *data, qint64 size);
0258 
0259     /**
0260      * Overload for writeData(const char *, qint64);
0261      * @since 6.0
0262      */
0263     bool writeData(QByteArrayView data);
0264 
0265     /**
0266      * Call finishWriting after writing the data.
0267      * @param size the size of the file
0268      * @see prepareWriting()
0269      */
0270     bool finishWriting(qint64 size);
0271 
0272 protected:
0273     /**
0274      * Opens an archive for reading or writing.
0275      * Called by open.
0276      * @param mode may be QIODevice::ReadOnly or QIODevice::WriteOnly
0277      */
0278     virtual bool openArchive(QIODevice::OpenMode mode) = 0;
0279 
0280     /**
0281      * Closes the archive.
0282      * Called by close.
0283      */
0284     virtual bool closeArchive() = 0;
0285 
0286     /**
0287      * Sets error description
0288      * @param errorStr error description
0289      * @since 5.29
0290      */
0291     void setErrorString(const QString &errorStr);
0292 
0293     /**
0294      * Retrieves or create the root directory.
0295      * The default implementation assumes that openArchive() did the parsing,
0296      * so it creates a dummy rootdir if none was set (write mode, or no '/' in the archive).
0297      * Reimplement this to provide parsing/listing on demand.
0298      * @return the root directory
0299      */
0300     virtual KArchiveDirectory *rootDir();
0301 
0302     /**
0303      * Write a directory to the archive.
0304      * This virtual method must be implemented by subclasses.
0305      *
0306      * Depending on the archive type not all metadata might be used.
0307      *
0308      * @param name the name of the directory
0309      * @param user the user that owns the directory
0310      * @param group the group that owns the directory
0311      * @param perm permissions of the directory. Use 040755 if you don't have any other information.
0312      * @param atime time the file was last accessed
0313      * @param mtime modification time of the file
0314      * @param ctime time of last status change
0315      * @see writeDir
0316      */
0317     virtual bool doWriteDir(const QString &name,
0318                             const QString &user,
0319                             const QString &group,
0320                             mode_t perm,
0321                             const QDateTime &atime,
0322                             const QDateTime &mtime,
0323                             const QDateTime &ctime) = 0;
0324 
0325     /**
0326      * Writes a symbolic link to the archive.
0327      * This virtual method must be implemented by subclasses.
0328      *
0329      * @param name name of symbolic link
0330      * @param target target of symbolic link
0331      * @param user the user that owns the directory
0332      * @param group the group that owns the directory
0333      * @param perm permissions of the directory
0334      * @param atime time the file was last accessed
0335      * @param mtime modification time of the file
0336      * @param ctime time of last status change
0337      * @see writeSymLink
0338      */
0339     virtual bool doWriteSymLink(const QString &name,
0340                                 const QString &target,
0341                                 const QString &user,
0342                                 const QString &group,
0343                                 mode_t perm,
0344                                 const QDateTime &atime,
0345                                 const QDateTime &mtime,
0346                                 const QDateTime &ctime) = 0;
0347 
0348     /**
0349      * This virtual method must be implemented by subclasses.
0350      *
0351      * Depending on the archive type not all metadata might be used.
0352      *
0353      * @param name the name of the file
0354      * @param user the user that owns the file
0355      * @param group the group that owns the file
0356      * @param size the size of the file
0357      * @param perm permissions of the file. Use 0100644 if you don't have any more specific permissions to set.
0358      * @param atime time the file was last accessed
0359      * @param mtime modification time of the file
0360      * @param ctime time of last status change
0361      * @see prepareWriting
0362      */
0363     virtual bool doPrepareWriting(const QString &name,
0364                                   const QString &user,
0365                                   const QString &group,
0366                                   qint64 size,
0367                                   mode_t perm,
0368                                   const QDateTime &atime,
0369                                   const QDateTime &mtime,
0370                                   const QDateTime &ctime) = 0;
0371 
0372     /**
0373      * Write data into the current file.
0374      * Called by writeData.
0375      *
0376      * @param data a pointer to the data
0377      * @param size the size of the chunk
0378      * @return @c true if successful, @c false otherwise
0379      * @see writeData
0380      * @since 6.0
0381      */
0382     virtual bool doWriteData(const char *data, qint64 size);
0383 
0384     /**
0385      * Called after writing the data.
0386      * This virtual method must be implemented by subclasses.
0387      *
0388      * @param size the size of the file
0389      * @see finishWriting()
0390      */
0391     virtual bool doFinishWriting(qint64 size) = 0;
0392 
0393     /**
0394      * Ensures that @p path exists, create otherwise.
0395      * This handles e.g. tar files missing directory entries, like mico-2.3.0.tar.gz :)
0396      * @param path the path of the directory
0397      * @return the directory with the given @p path
0398      */
0399     KArchiveDirectory *findOrCreate(const QString &path);
0400 
0401     /**
0402      * Can be reimplemented in order to change the creation of the device
0403      * (when using the fileName constructor). By default this method uses
0404      * QSaveFile when saving, and a simple QFile on reading.
0405      * This method is called by open().
0406      */
0407     virtual bool createDevice(QIODevice::OpenMode mode);
0408 
0409     /**
0410      * Can be called by derived classes in order to set the underlying device.
0411      * Note that KArchive will -not- own the device, it must be deleted by the derived class.
0412      */
0413     void setDevice(QIODevice *dev);
0414 
0415     /**
0416      * Derived classes call setRootDir from openArchive,
0417      * to set the root directory after parsing an existing archive.
0418      */
0419     void setRootDir(KArchiveDirectory *rootDir);
0420 
0421 protected:
0422     virtual void virtual_hook(int id, void *data);
0423 
0424 private:
0425     friend class KArchivePrivate;
0426     KArchivePrivate *const d;
0427 };
0428 
0429 // for source compat
0430 #include "karchivedirectory.h"
0431 #include "karchivefile.h"
0432 
0433 #endif