quickmod/FuseMounter/modarchive.cpp

245 lines
6.4 KiB
C++
Raw Normal View History

#include "modarchive.h"
//#include <archive_entry.h>
#include <fcntl.h>
#include <unistd.h>
#include <QDebug>
#define BLOCKSIZE 10240
Archive::Archive(const QString &arcpath, QObject *parent)
: QObject{parent},
m_stream{NULL},
m_archive{NULL},
m_arcpath{arcpath},
m_suicidal{false}
{
if( !this->open() )
return;
qDebug() << "Archive:" << arcpath;
while( ar_parse_entry(m_archive) )
{
const char *entryname = ar_entry_get_name(m_archive);
if( strlen(entryname) <= 0 )
continue;
/*
if( (st->st_mode & S_IFMT) == S_IFDIR )
continue;
*/
time64_t filetime = ar_entry_get_filetime(m_archive) / 100000000;
ArchiveCacheEntry *cacheEntry = new ArchiveCacheEntry(this);
cacheEntry->m_offset = ar_entry_get_offset(m_archive);
memset( (void*)&cacheEntry->m_stat, 0, sizeof(struct stat) );
cacheEntry->m_stat.st_size = ar_entry_get_size(m_archive);
cacheEntry->m_stat.st_mode = S_IFREG | 0755;
cacheEntry->m_stat.st_nlink = 1;
cacheEntry->m_stat.st_uid = geteuid();
cacheEntry->m_stat.st_gid = getegid();
cacheEntry->m_stat.st_atim.tv_sec = filetime;
cacheEntry->m_stat.st_mtim.tv_sec = filetime;
cacheEntry->m_stat.st_ctim.tv_sec = filetime;
QString lpath = QString(entryname).toLower();
m_cache.insert( lpath, cacheEntry );
//qDebug() << "\tAdding" << lpath << "/" << cacheEntry->m_stat.st_size << "bytes at offset" << cacheEntry->m_offset;
}
}
Archive::~Archive()
{
for( ArchiveCacheEntry *ent : m_cache.values() )
ent->deleteLater();
close();
}
bool Archive::open()
{
m_stream = ar_open_file(m_arcpath.toStdString().c_str());
if( !m_stream ) {
qDebug() << "Failed to open archive stream:" << m_arcpath;
return false;
}
if( m_arcpath.endsWith("7z", Qt::CaseInsensitive) )
m_archive = ar_open_7z_archive(m_stream);
else if( m_arcpath.endsWith("rar", Qt::CaseInsensitive) )
m_archive = ar_open_rar_archive(m_stream);
else if( m_arcpath.endsWith("zip", Qt::CaseInsensitive) )
m_archive = ar_open_zip_archive(m_stream, false);
else {
qDebug() << "Unsupported archive type:" << m_arcpath;
return false;
}
if( !m_archive )
qDebug() << "Failed to open archive:" << m_arcpath;
return NULL != m_archive;
}
bool Archive::close()
{
if( !m_archive )
return false;
m_archive = NULL;
m_stream = NULL;
ar_close_archive(m_archive);
ar_close(m_stream);
return true;
}
bool Archive::contains(const QString &path)
{
QString lpath = path.toLower();
return m_cache.contains(lpath);
}
QMap< QString, ArchiveCacheEntry * > *Archive::getEntries()
{
return &m_cache;
}
QByteArray *Archive::getEntry(const QString &path)
{
QString lpath = path.toLower();
if( !m_cache.contains(lpath) ) {
qDebug() << " 918273918273918273 NOT FOUND:" << lpath;
return NULL; // Not found.
}
else if( m_cache[lpath]->m_loading ) {
//qDebug() << QString("getEntry(%1) -> (Still Loading...)\n").arg(path);
qDebug() << "Archive::getEntry: Already loading, chill.";
return NULL;
}
else if( m_cache[lpath]->m_cached ) {
//qDebug() << QString("getEntry(%1) -> CACHED\n").arg(path);
m_cache[lpath]->m_lastAccess = time(NULL);
m_cache[lpath]->m_accessCount++;
m_cache[lpath]->m_locked = true;
m_cache[lpath]->m_mutex.lock();
return &m_cache[lpath]->m_data;
}
m_cache[lpath]->m_loading = true;
m_mutex.lock();
qDebug() << "Cheaty skip to" << m_cache[lpath]->m_offset << "bytes...";
if( !ar_parse_entry_at(m_archive, m_cache[lpath]->m_offset) ) {
qDebug() << "Archive::getEntry: ar_parse_entry_at failed!";
m_cache[lpath]->m_loading = false;
m_mutex.unlock();
return NULL;
}
//int64_t entrysize = archive_entry_size(entry);
QByteArray obuf;
char buff[BLOCKSIZE * 256];
size_t len = sizeof(buff);
if( len > (size_t)m_cache[lpath]->m_stat.st_size )
len = m_cache[lpath]->m_stat.st_size;
while( ar_entry_uncompress(m_archive, buff, len ) ) {
obuf.append(buff, len);
len = m_cache[lpath]->m_stat.st_size - obuf.length();
if( len <= 0 )
break;
if( len > sizeof(buff) )
len = sizeof(buff);
}
m_mutex.unlock();
if( 0 > obuf.length() ) {
m_cache[lpath]->m_loading = false;
return NULL;
}
m_cache[lpath]->m_data = obuf;
m_cache[lpath]->m_cached = true;
m_cache[lpath]->m_accessCount++;
m_cache[lpath]->m_loading = false;
m_cache[lpath]->m_lastAccess = time(NULL);
m_cache[lpath]->m_locked = true;
m_cache[lpath]->m_mutex.lock();
return &m_cache[lpath]->m_data;
}
void Archive::releaseEntry(const QString &path)
{
QString lpath = path.toLower();
if( !m_cache.contains(lpath) ) {
qDebug() << " releaseEntry: ---1231231 NOT FOUND:" << lpath;
return; // Not found.
}
/*
m_cache[lpath]->m_cached = false;
m_cache[lpath]->m_mutex.unlock();
m_cache[lpath]->m_locked = false;
m_cache[lpath]->m_data.clear();
*/
m_cache[lpath]->m_mutex.unlock();
m_cache[lpath]->m_locked = false;
if( m_suicidal )
checkIfLifeIsWorthIt();
}
ArchiveCacheEntry *Archive::cache(const QString &path)
{
QString lpath = path.toLower();
if( !m_cache.contains(lpath) )
return NULL;
return m_cache[lpath];
}
void Archive::cleanCache(time_t olderThan)
{
//return;
QStringList keys = m_cache.keys();
for( const QString &k : keys )
{
if( !m_cache[k]->m_cached )
continue;
if( m_cache[k]->m_loading )
continue;
if( m_cache[k]->m_locked )
continue;
if( m_cache[k]->m_lastAccess > olderThan )
continue;
qDebug() << "Archive::cleanCache: Clearing cache entry for:" << k;
m_cache[k]->m_mutex.lock();
m_cache[k]->m_cached = false;
m_cache[k]->m_data.clear();
m_cache[k]->m_mutex.unlock();
}
}
void Archive::killme()
{
m_suicidal = true;
checkIfLifeIsWorthIt();
}
void Archive::checkIfLifeIsWorthIt()
{
for( QString k : m_cache.keys() )
{
if( m_cache[k]->m_loading )
return;
if( m_cache[k]->m_locked )
return;
}
deleteLater();
}