File indexing completed on 2025-01-26 04:14:57

0001 /*
0002  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) version 3, or any
0008  * later version accepted by the membership of KDE e.V. (or its
0009  * successor approved by the membership of KDE e.V.), which shall
0010  * act as a proxy defined in Section 6 of version 3 of the license.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0019  *
0020  */
0021 
0022 #include "KRar.h"
0023 #include "KRarFileEntry.h"
0024 
0025 #include <QtCore/QDir>
0026 #include <QtCore/QFile>
0027 #include <QtCore/QIODevice>
0028 #include <QDebug>
0029 
0030 extern "C"
0031 {
0032     #include <unarr.h>
0033 }
0034 
0035 class KRar::Private {
0036 public:
0037     Private()
0038         : archive(nullptr)
0039         , stream(nullptr)
0040     {}
0041     ar_archive* archive;
0042     ar_stream* stream;
0043     QList<KRarFileEntry*> files;
0044 };
0045 
0046 KRar::KRar(const QString& filename)
0047     : KArchive(filename)
0048     , d(new Private)
0049 {
0050 }
0051 
0052 KRar::KRar(QIODevice* dev)
0053     : KArchive(dev)
0054     , d(new Private)
0055 {
0056 }
0057 
0058 KRar::~KRar()
0059 {
0060     if (isOpen()) {
0061         close();
0062     }
0063     delete d;
0064 }
0065 
0066 bool KRar::doPrepareWriting(const QString& /*name*/, const QString& /*user*/, const QString& /*group*/, qint64 /*size*/, mode_t /*perm*/, const QDateTime& /*atime*/, const QDateTime& /*mtime*/, const QDateTime& /*ctime*/)
0067 {
0068     return false;
0069 }
0070 
0071 bool KRar::doFinishWriting(qint64 /*size*/)
0072 {
0073     return false;
0074 }
0075 
0076 bool KRar::doWriteDir(const QString& /*name*/, const QString& /*user*/, const QString& /*group*/, mode_t /*perm*/, const QDateTime& /*atime*/, const QDateTime& /*mtime*/, const QDateTime& /*ctime*/)
0077 {
0078     return false;
0079 }
0080 
0081 bool KRar::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*/)
0082 {
0083     return false;
0084 }
0085 
0086 bool KRar::openArchive(QIODevice::OpenMode mode)
0087 {
0088     // First clear the file list, because we don't like leftovers
0089     if(d->archive)
0090     {
0091         closeArchive();
0092     }
0093     // Open archive
0094 
0095     if (mode == QIODevice::WriteOnly) {
0096         return true;
0097     }
0098     if (mode != QIODevice::ReadOnly && mode != QIODevice::ReadWrite) {
0099         //qWarning() << "Unsupported mode " << mode;
0100         return false;
0101     }
0102 
0103     QIODevice *dev = device();
0104     if (!dev) {
0105         return false;
0106     }
0107 
0108     d->stream = ar_open_file(fileName().toLocal8Bit());
0109     if (!d->stream)
0110     {
0111         qDebug() << "Failed to open" << fileName() << "into a stream for unarr";
0112         return false;
0113     }
0114 
0115     d->archive = ar_open_rar_archive(d->stream);
0116     if (!d->archive)
0117     {
0118         qDebug() << "Failed to open" << fileName() << "as a rar archive. Are we sure this is a rar archive?";
0119         return false;
0120     }
0121 
0122     // Iterate through all entries and get a KRarFileEntry out of them
0123     while (ar_parse_entry(d->archive)) {
0124         QString pathname(ar_entry_get_name(d->archive));
0125         int splitPos = pathname.lastIndexOf("/");
0126         QString path = pathname.left(splitPos);
0127         QString name = pathname.mid(splitPos + 1);
0128         QDateTime mtime = QDateTime::fromTime_t(ar_entry_get_filetime(d->archive));
0129         quint64 start = ar_entry_get_offset(d->archive);
0130         quint64 size = ar_entry_get_size(d->archive);
0131         // So, funny thing - unarr ignores directory entries in rar files entirely (see unarr/rar/rar.c:65)
0132         // Leaving the code in, in case we feel like reintroducing this at a later point in time
0133 //         bool isDir = size < 1;//archive_entry_filetype(entry) == AE_IFDIR;
0134 
0135         KArchiveEntry* kaentry = nullptr;
0136 //         if(isDir)
0137 //         {
0138 //             QString path = QDir::cleanPath(pathname);
0139 //             const KArchiveEntry *ent = rootDir()->entry(path);
0140 //             if (ent && ent->isDirectory()) {
0141 //                 qDebug() << "Directory already exists, NOT going to add it again";
0142 //                 kaentry = 0;
0143 //             } else {
0144 //                 kaentry = new KArchiveDirectory(this, name, 0755, mtime, rootDir()->user(), rootDir()->group(), QString());
0145 //                 qDebug() << "KArchiveDirectory created, name=" << name;
0146 //             }
0147 //         }
0148 //         else
0149 //         {
0150             KRarFileEntry* fileEntry = new KRarFileEntry(this, name, 0100644, mtime, rootDir()->user(), rootDir()->group(), "", path, start, size, d->archive);
0151             kaentry = fileEntry;
0152             d->files.append(fileEntry);
0153 //         }
0154 
0155         if(kaentry)
0156         {
0157             if(splitPos > 0)
0158             {
0159                 // Ensure container directory exists, create otherwise
0160                 KArchiveDirectory *tdir = findOrCreate(path);
0161                 tdir->addEntry(kaentry);
0162             }
0163             else
0164             {
0165                 rootDir()->addEntry(kaentry);
0166             }
0167         }
0168     }
0169 
0170     return true;
0171 }
0172 
0173 bool KRar::closeArchive()
0174 {
0175     ar_close_archive(d->archive);
0176     ar_close(d->stream);
0177     d->archive = nullptr;
0178     d->stream = nullptr;
0179     qDeleteAll(d->files);
0180     d->files.clear();
0181     return true;
0182 }
0183 
0184 void KRar::virtual_hook(int id, void* data)
0185 {
0186     KArchive::virtual_hook(id, data);
0187 }