840 lines
23 KiB
C++
840 lines
23 KiB
C++
#include "fuseinterface.h"
|
|
#include "fusebase.h"
|
|
#include "fusearchive.h"
|
|
#include "fuseproxy.h"
|
|
#include "fusesandbox.h"
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/mount.h>
|
|
|
|
#define CACHE_ENABLED true
|
|
//#define FUSE_DEBUG 1
|
|
|
|
FuseInterface::FuseInterface(QSqlDatabase &database, int profileId, const QString &gameDataDir, const QString &sandboxDir, const QString &mountpoint, QObject *parent)
|
|
: QObject{parent},
|
|
m_fuse_id{0},
|
|
m_fuse{nullptr},
|
|
m_fuse_session{nullptr},
|
|
m_notifier{nullptr},
|
|
m_database{database},
|
|
m_profileId{profileId},
|
|
m_gameDataDir{gameDataDir},
|
|
m_sandboxDir{sandboxDir},
|
|
m_mountpoint{mountpoint}
|
|
{
|
|
// Default to 512MB
|
|
m_cache_data.setMaxCost(512 * 1024 * 1024);
|
|
}
|
|
|
|
FuseInterface::~FuseInterface()
|
|
{
|
|
}
|
|
|
|
bool FuseInterface::mount() {
|
|
char mpoint[8192];
|
|
|
|
std::string mountStr = m_mountpoint.toStdString();
|
|
strncpy(mpoint, mountStr.c_str(), sizeof(mpoint)-1);
|
|
|
|
// Prefer options before mountpoint so fuse_parse_cmdline finds them reliably
|
|
char *argv[] = {
|
|
const_cast<char *>("quickmod"),
|
|
const_cast<char *>("-f"),
|
|
const_cast<char *>("-o"),
|
|
const_cast<char *>("auto_unmount"),
|
|
mpoint,
|
|
nullptr
|
|
};
|
|
|
|
int argc = sizeof(argv) / sizeof(argv[0]) - 1;
|
|
struct fuse_args args = FUSE_ARGS_INIT(argc, (char **)argv);
|
|
struct fuse_cmdline_opts opts;
|
|
|
|
if( 0 != fuse_parse_cmdline(&args, &opts) ) {
|
|
qCritical() << "Failed to parse options?";
|
|
return false;
|
|
}
|
|
|
|
struct fuse_operations qmfuse_oper;
|
|
memset( &qmfuse_oper, 0, sizeof(struct fuse_operations) );
|
|
|
|
qmfuse_oper.getattr = f_getattr;
|
|
qmfuse_oper.mkdir = f_mkdir;
|
|
qmfuse_oper.unlink = f_unlink;
|
|
qmfuse_oper.rmdir = f_rmdir;
|
|
//qmfuse_oper.truncate = f_truncate;
|
|
qmfuse_oper.open = f_open;
|
|
qmfuse_oper.read = f_read;
|
|
qmfuse_oper.write = f_write;
|
|
qmfuse_oper.release = f_release;
|
|
qmfuse_oper.readdir = f_readdir;
|
|
qmfuse_oper.create = f_create;
|
|
//qmfuse_oper.lseek = f_lseek;
|
|
|
|
size_t op_size = sizeof(qmfuse_oper);
|
|
m_fuse = fuse_new(&args, &qmfuse_oper, op_size, this);
|
|
if( !m_fuse ) {
|
|
qCritical() << "Failed to create new FUSE object.";
|
|
return false;
|
|
}
|
|
|
|
if( 0 != fuse_mount(m_fuse, mpoint) ) {
|
|
qCritical() << "Failed at fuse_mount!";
|
|
fuse_destroy(m_fuse);
|
|
return false;
|
|
}
|
|
|
|
m_fuse_session = fuse_get_session(m_fuse);
|
|
if( 0 != fuse_set_signal_handlers(m_fuse_session) ) {
|
|
qCritical() << "Failed to set FUSE signal handlers!";
|
|
return false;
|
|
}
|
|
|
|
m_fuse_id = fuse_session_fd(m_fuse_session);
|
|
if( m_notifier )
|
|
m_notifier->deleteLater();
|
|
|
|
m_notifier = new QSocketNotifier(m_fuse_id, QSocketNotifier::Read, this);
|
|
QObject::connect( m_notifier, &QSocketNotifier::activated, this, &FuseInterface::pump );
|
|
|
|
qDebug() << "Mounted OKAY.";
|
|
init();
|
|
|
|
return true;
|
|
}
|
|
|
|
int FuseInterface::pump()
|
|
{
|
|
int ret = 0;
|
|
do {
|
|
struct fuse_buf fbuf;
|
|
memset(&fbuf, 0, sizeof(struct fuse_buf));
|
|
|
|
if( fuse_session_exited(m_fuse_session) ) {
|
|
qDebug() << "Feh. Session closed!";
|
|
deleteLater();
|
|
return -1;
|
|
}
|
|
|
|
ret = fuse_session_receive_buf(m_fuse_session, &fbuf);
|
|
if( -EINTR == ret )
|
|
return 0; // Nothing to do.
|
|
|
|
if( 0 >= ret )
|
|
return ret;
|
|
|
|
fuse_session_process_buf(m_fuse_session, &fbuf);
|
|
} while(0 == ret);
|
|
return ret;
|
|
}
|
|
|
|
void FuseInterface::unmount()
|
|
{
|
|
if( m_notifier ) {
|
|
m_notifier->setEnabled(false);
|
|
m_notifier->deleteLater();
|
|
}
|
|
m_notifier = nullptr;
|
|
|
|
// Stop handling signals and mark session as exiting to quiesce activity
|
|
if( m_fuse_session ) {
|
|
fuse_remove_signal_handlers(m_fuse_session);
|
|
fuse_session_exit(m_fuse_session);
|
|
}
|
|
|
|
// Perform a lazy unmount to succeed even if handles are flushing
|
|
// This detaches the mount and completes once all refs are closed
|
|
if (!m_mountpoint.isEmpty()) {
|
|
::umount2(m_mountpoint.toStdString().c_str(), MNT_DETACH);
|
|
}
|
|
|
|
if( m_fuse )
|
|
{
|
|
fuse_unmount(m_fuse);
|
|
fuse_destroy(m_fuse);
|
|
}
|
|
|
|
m_fuse = nullptr;
|
|
m_fuse_session = nullptr;
|
|
deleteLater();
|
|
}
|
|
|
|
void FuseInterface::init()
|
|
{
|
|
clear();
|
|
m_mutex.lock();
|
|
|
|
QString sandboxDir = m_sandboxDir + QDir::separator() + QString::number(m_profileId);
|
|
FuseAccessorSandbox *sandbox = new FuseAccessorSandbox(this, sandboxDir);
|
|
qDebug() << "Adding sandbox dir path:" << sandboxDir;
|
|
append(sandbox);
|
|
|
|
QList< FuseProxyMapping > proxypaths = FuseAccessorProxy::proxyList(m_database, m_profileId);
|
|
FuseAccessorProxy *pent = new FuseAccessorProxy(this, proxypaths);
|
|
append(pent);
|
|
|
|
QList< QPair<int, QString> > activeArchives = FuseAccessorArchive::activeArchives(m_database, m_profileId);
|
|
for( const QPair<int, QString> &arc : std::as_const(activeArchives) )
|
|
{
|
|
qDebug() << "Adding archive:" << arc.second;
|
|
FuseAccessorArchive *aent = new FuseAccessorArchive(this, m_database, arc.first, arc.second);
|
|
append(aent);
|
|
}
|
|
|
|
FuseAccessorProxy *vanilla = new FuseAccessorProxy(this, m_gameDataDir);
|
|
qDebug() << "Adding game data dir path:" << m_gameDataDir;
|
|
append(vanilla);
|
|
|
|
m_mutex.unlock();
|
|
}
|
|
|
|
void FuseInterface::clear()
|
|
{
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
fab->deleteLater();
|
|
}
|
|
m_accessors.clear();
|
|
m_dircache.clear();
|
|
for( struct stat *st : std::as_const(m_cache_stat) )
|
|
free(st);
|
|
m_cache_stat.clear();
|
|
m_cache_accessor.clear();
|
|
m_cache_data.clear();
|
|
// TODO: m_watcher?
|
|
m_stats.clear();
|
|
m_mutex.unlock();
|
|
}
|
|
|
|
void FuseInterface::prepend(FuseAccessorBase *accessor)
|
|
{
|
|
m_accessors.prepend(accessor);
|
|
}
|
|
|
|
void FuseInterface::append(FuseAccessorBase *accessor)
|
|
{
|
|
m_accessors.append(accessor);
|
|
}
|
|
|
|
void FuseInterface::remove(FuseAccessorBase *accessor)
|
|
{
|
|
m_accessors.removeOne(accessor);
|
|
accessor->deleteLater();
|
|
}
|
|
/*
|
|
int FuseInterface::utilQPermsToMode(QFileDevice::Permissions mode)
|
|
{
|
|
int smode = 0;
|
|
if( QFileDevice::ReadUser & mode ) smode += S_IRUSR;
|
|
if( QFileDevice::WriteUser & mode ) smode += S_IWUSR;
|
|
if( QFileDevice::ExeUser & mode ) smode += S_IXUSR;
|
|
|
|
if( QFileDevice::ReadGroup & mode ) smode += S_IRGRP;
|
|
if( QFileDevice::WriteGroup & mode ) smode += S_IWGRP;
|
|
if( QFileDevice::ExeGroup & mode ) smode += S_IXGRP;
|
|
|
|
if( QFileDevice::ReadOther & mode ) smode += S_IROTH;
|
|
if( QFileDevice::WriteOther & mode ) smode += S_IWOTH;
|
|
if( QFileDevice::ExeOther & mode ) smode += S_IXOTH;
|
|
return smode;
|
|
}
|
|
*/
|
|
FuseFHBase *FuseInterface::makeWritableFromSource(const QString &source, const QString &origsource, const QString &dest, QIODeviceBase::OpenMode mode)
|
|
{
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
FuseAccessorSandbox *sandbox = reinterpret_cast<FuseAccessorSandbox *>(fab);
|
|
FuseFHBase *fh = sandbox->makeWritableFromSource(source, origsource, dest, mode);
|
|
m_mutex.unlock();
|
|
return fh;
|
|
}
|
|
m_mutex.unlock();
|
|
return NULL;
|
|
}
|
|
|
|
FuseFHBase *FuseInterface::makeWritableFromData(const QByteArray &source, const QString &origsource, const QString &dest, QIODeviceBase::OpenMode mode)
|
|
{
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
FuseAccessorSandbox *sandbox = reinterpret_cast<FuseAccessorSandbox *>(fab);
|
|
FuseFHBase *fh = sandbox->makeWritableFromData(source, origsource, dest, mode);
|
|
|
|
m_mutex.unlock();
|
|
return fh;
|
|
}
|
|
m_mutex.unlock();
|
|
return NULL;
|
|
}
|
|
|
|
// don't look at me, don't look at me! guhhhh~~!!!
|
|
static QString humanSize(qint64 bytes)
|
|
{
|
|
static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB" };
|
|
double size = bytes;
|
|
int i = 0;
|
|
while (size >= 1024.0 && i < 4) {
|
|
size /= 1024.0;
|
|
++i;
|
|
}
|
|
return QString::number(size, 'f', (i == 0 ? 0 : 2)) + ' ' + suffixes[i];
|
|
}
|
|
|
|
void FuseInterface::cacheInsert(const QString &path, QByteArray &data)
|
|
{
|
|
if( data.isEmpty() )
|
|
return;
|
|
|
|
QSharedPointer<QByteArray> sharedData = QSharedPointer<QByteArray>::create(std::move(data));
|
|
QSharedPointer<QByteArray> *val = new QSharedPointer<QByteArray>(std::move(sharedData));
|
|
m_cache_data.insert(path, val, val->data()->size());
|
|
qDebug() << " - m_cache_data now contains" << m_cache_data.size() << "entries, totalling" << humanSize(m_cache_data.totalCost()) << "bytes";
|
|
|
|
emit entryUpdated(path, "Archive", 1, 1);
|
|
}
|
|
|
|
QSharedPointer<QByteArray> FuseInterface::cacheGrab(const QString &path)
|
|
{
|
|
if( !m_cache_data.contains(path) )
|
|
return {};
|
|
auto *p = m_cache_data.object(path);
|
|
return *p;
|
|
}
|
|
|
|
int FuseInterface::getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(fi)
|
|
|
|
int ret;
|
|
QString qpath(path);
|
|
|
|
if( CACHE_ENABLED && m_cache_stat.contains(qpath) )
|
|
{
|
|
if( !m_cache_stat[qpath] )
|
|
return -ENOENT;
|
|
|
|
memcpy( stbuf, m_cache_stat[qpath], sizeof(struct stat) );
|
|
return 0;
|
|
}
|
|
|
|
for( FuseAccessorBase *ent : std::as_const(m_accessors) )
|
|
{
|
|
ret = ent->getattr(qpath, stbuf);
|
|
if( 0 == ret ) {
|
|
struct stat *scache = (struct stat *)malloc(sizeof(struct stat));
|
|
memcpy( scache, stbuf, sizeof(struct stat) );
|
|
m_cache_stat.insert(qpath, scache);
|
|
m_cache_accessor.insert(qpath, ent);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
m_cache_stat.insert(qpath, NULL);
|
|
return -ENOENT;
|
|
}
|
|
|
|
int FuseInterface::create(const char *path, mode_t mode, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(fi)
|
|
|
|
int ret = 1;
|
|
QString qpath(path);
|
|
FuseAccessorSandbox *sb = NULL;
|
|
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
sb = qobject_cast<FuseAccessorSandbox *>(fab);
|
|
QFileDevice::Permissions qmode = (QFileDevice::Permissions)mode;
|
|
ret = sb->create(qpath, qmode);
|
|
break;
|
|
}
|
|
|
|
if( CACHE_ENABLED && m_cache_stat.contains(qpath) )
|
|
{
|
|
struct stat *st = m_cache_stat.take(qpath);
|
|
if( st )
|
|
free(st);
|
|
}
|
|
|
|
m_mutex.unlock();
|
|
if( 0 == ret && sb )
|
|
return open(path, fi);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int FuseInterface::mkdir(const char *path, mode_t mode)
|
|
{
|
|
int ret = 1;
|
|
QString qpath(path);
|
|
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
FuseAccessorSandbox *sb = qobject_cast<FuseAccessorSandbox *>(fab);
|
|
QFileDevice::Permissions qmode = (QFileDevice::Permissions)mode;
|
|
ret = sb->mkdir(qpath, qmode);
|
|
break;
|
|
}
|
|
|
|
if( CACHE_ENABLED ) {
|
|
if( m_cache_stat.contains(qpath) )
|
|
{
|
|
struct stat *st = m_cache_stat.take(qpath);
|
|
if( st )
|
|
free(st);
|
|
}
|
|
if( m_dircache.contains(qpath) )
|
|
m_dircache.remove(qpath);
|
|
}
|
|
|
|
m_mutex.unlock();
|
|
return ret;
|
|
}
|
|
|
|
int FuseInterface::unlink(const char *path)
|
|
{
|
|
int ret = 1;
|
|
QString qpath(path);
|
|
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
FuseAccessorSandbox *sb = qobject_cast<FuseAccessorSandbox *>(fab);
|
|
ret = sb->unlink(qpath);
|
|
break;
|
|
}
|
|
|
|
if( CACHE_ENABLED ) {
|
|
if( m_cache_stat.contains(qpath) )
|
|
{
|
|
struct stat *st = m_cache_stat.take(qpath);
|
|
if( st )
|
|
free(st);
|
|
}
|
|
if( m_dircache.contains(qpath) )
|
|
m_dircache.remove(qpath);
|
|
}
|
|
|
|
m_mutex.unlock();
|
|
return ret;
|
|
}
|
|
|
|
int FuseInterface::rmdir(const char *path)
|
|
{
|
|
int ret = 1;
|
|
QString qpath(path);
|
|
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
FuseAccessorSandbox *sb = qobject_cast<FuseAccessorSandbox *>(fab);
|
|
ret = sb->rmdir(qpath);
|
|
break;
|
|
}
|
|
|
|
if( CACHE_ENABLED ) {
|
|
if( m_cache_stat.contains(qpath) )
|
|
{
|
|
struct stat *st = m_cache_stat.take(qpath);
|
|
if( st )
|
|
free(st);
|
|
}
|
|
if( m_dircache.contains(qpath) )
|
|
m_dircache.remove(qpath);
|
|
}
|
|
|
|
m_mutex.unlock();
|
|
return ret;
|
|
}
|
|
|
|
int FuseInterface::rename(const char *path, const char *newname, unsigned int flags)
|
|
{
|
|
Q_UNUSED(path)
|
|
Q_UNUSED(newname)
|
|
Q_UNUSED(flags)
|
|
return 1;
|
|
}
|
|
|
|
int FuseInterface::truncate(const char *path, off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(fi)
|
|
int ret = 1;
|
|
QString qpath(path);
|
|
|
|
m_mutex.lock();
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
|
|
continue;
|
|
|
|
FuseAccessorSandbox *sb = qobject_cast<FuseAccessorSandbox *>(fab);
|
|
ret = sb->truncate(qpath, offset);
|
|
break;
|
|
}
|
|
|
|
if( CACHE_ENABLED && m_cache_stat.contains(qpath) )
|
|
{
|
|
struct stat *st = m_cache_stat.take(qpath);
|
|
if( st )
|
|
free(st);
|
|
}
|
|
|
|
m_mutex.unlock();
|
|
return ret;
|
|
}
|
|
|
|
#ifndef FUSE_FILL_DIR_DEFAULTS
|
|
constexpr fuse_fill_dir_flags FUSE_FILL_DIR_DEFAULTS = static_cast<fuse_fill_dir_flags>(0);
|
|
#endif
|
|
int FuseInterface::readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags)
|
|
{
|
|
Q_UNUSED(offset)
|
|
Q_UNUSED(fi)
|
|
Q_UNUSED(flags)
|
|
|
|
QString qpath(path);
|
|
if( CACHE_ENABLED && m_dircache.contains(qpath) )
|
|
{
|
|
QStringList ents = m_dircache[qpath];
|
|
for( const QString &ent : std::as_const(ents) )
|
|
filler(buf, ent.toStdString().c_str(), NULL, 0, FUSE_FILL_DIR_DEFAULTS);
|
|
return 0;
|
|
}
|
|
|
|
QStringList ents, lents;
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
QStringList dir = fab->readdir(QString(path));
|
|
for( const QStringView nent : std::as_const(dir) )
|
|
{
|
|
QString blorp = nent.toString();
|
|
QString lc = blorp.toLower();
|
|
if( lents.contains(lc) )
|
|
continue;
|
|
|
|
filler(buf, blorp.toStdString().c_str(), NULL, 0, FUSE_FILL_DIR_DEFAULTS);
|
|
ents.append(blorp);
|
|
lents.append(lc);
|
|
}
|
|
}
|
|
|
|
if( CACHE_ENABLED )
|
|
m_dircache[qpath] = ents;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int FuseInterface::write(const char *path, const char *buf, size_t bufsz, off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(path)
|
|
FuseFHBase *fhbase = reinterpret_cast<FuseFHBase *>(fi->fh);
|
|
qDebug() << "FuseFHBase:" << fhbase;
|
|
|
|
//FuseAccessorBase *fabase = fhbase->getAccessor();
|
|
/*
|
|
qDebug() << "fabase:" << fabase;
|
|
qDebug() << "Type:" << fabase->getType();
|
|
*/
|
|
|
|
FuseFHBase *sfh = qobject_cast<FuseFHBase *>(fhbase);
|
|
QByteArray data(buf, bufsz);
|
|
return sfh->write(data, offset, fi);
|
|
}
|
|
|
|
int FuseInterface::open(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
int fam = (fi->flags & O_ACCMODE);
|
|
|
|
QString qpath(path);
|
|
QIODeviceBase::OpenMode qmode;
|
|
switch( fam )
|
|
{
|
|
case O_RDWR:
|
|
qmode = QIODeviceBase::ReadWrite;
|
|
if( !( O_TRUNC & fi->flags ) )
|
|
qmode |= QIODeviceBase::Append;
|
|
|
|
break;
|
|
case O_WRONLY:
|
|
qmode = QIODeviceBase::WriteOnly;
|
|
if( !( O_TRUNC & fi->flags ) )
|
|
qmode |= QIODeviceBase::Append;
|
|
|
|
break;
|
|
default:
|
|
qmode = QIODeviceBase::ReadOnly;
|
|
}
|
|
|
|
if( !( O_CREAT & fi->flags ) )
|
|
qmode |= QIODeviceBase::ExistingOnly;
|
|
|
|
// STATS:
|
|
VFSStatEntry se { qpath, QDateTime::currentSecsSinceEpoch(), 0, 0 };
|
|
|
|
if( CACHE_ENABLED
|
|
&& QIODeviceBase::ReadOnly & qmode
|
|
&& m_cache_accessor.contains(qpath) )
|
|
{
|
|
FuseAccessorBase *fab = m_cache_accessor[qpath];
|
|
FuseFHBase *fh = fab->open(qpath, qmode);
|
|
if( fh ) {
|
|
fi->fh = reinterpret_cast<quint64>(fh);
|
|
m_open_handles.prepend(fh);
|
|
|
|
if( !m_stats.contains(qpath) ) {
|
|
qDebug() << "Adding1" << qpath;
|
|
m_stats.insert(qpath, se);
|
|
}
|
|
m_stats[qpath].openCount++;
|
|
m_stats[qpath].refCount++;
|
|
emit entryUpdated(qpath, fab->getResource(), m_stats[qpath].openCount, m_stats[qpath].refCount);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
|
|
{
|
|
/*
|
|
// FIXME: No no, we iterate through all:
|
|
if( FuseAccessorBase::FH_SANDBOX != fab->getType()
|
|
&& QIODeviceBase::WriteOnly == qmode )
|
|
continue;
|
|
*/
|
|
FuseFHBase *fh = fab->open(qpath, qmode);
|
|
if( !fh )
|
|
continue;
|
|
|
|
fi->fh = reinterpret_cast<quint64>(fh);
|
|
m_open_handles.prepend(fh);
|
|
|
|
if( !m_stats.contains(qpath) ) {
|
|
qDebug() << "Adding2" << qpath;
|
|
m_stats.insert(qpath, se);
|
|
}
|
|
m_stats[qpath].openCount++;
|
|
m_stats[qpath].refCount++;
|
|
emit entryUpdated(qpath, fab->getResource(), m_stats[qpath].openCount, m_stats[qpath].refCount);
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -EACCES;
|
|
}
|
|
|
|
int FuseInterface::release(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(path)
|
|
|
|
FuseFHBase *fhbase = reinterpret_cast<FuseFHBase *>(fi->fh);
|
|
|
|
QString qpath = fhbase->getPath();
|
|
VFSStatEntry se { qpath, QDateTime::currentSecsSinceEpoch(), 0, 0 };
|
|
if( !m_stats.contains(qpath) )
|
|
qDebug() << "Warning:" << qpath << "release, wasn't opened. Name was changed?";
|
|
else {
|
|
m_stats[qpath].refCount--;
|
|
emit entryUpdated(qpath, fhbase->getAccessor()->getResource(), m_stats[qpath].openCount, m_stats[qpath].refCount);
|
|
}
|
|
|
|
m_open_handles.removeOne(fhbase);
|
|
|
|
fhbase->release();
|
|
fhbase->deleteLater();
|
|
return 0;
|
|
}
|
|
|
|
int FuseInterface::read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(path)
|
|
|
|
FuseFHBase *fhbase = reinterpret_cast<FuseFHBase *>(fi->fh);
|
|
QByteArray data = fhbase->read(size, offset);
|
|
if( data.isEmpty() )
|
|
return 0;
|
|
|
|
::memcpy( buf, (void *)data.constData(), data.length() );
|
|
return data.length();
|
|
}
|
|
|
|
off_t FuseInterface::lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(path)
|
|
|
|
FuseFHBase *fhbase = reinterpret_cast<FuseFHBase *>(fi->fh);
|
|
//FuseAccessorBase *fabase = fhbase->getAccessor();
|
|
return fhbase->lseek(off, whence);
|
|
}
|
|
|
|
|
|
// FUSE glue:
|
|
int FuseInterface::f_getattr(const char *path, struct stat *stbuf,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->getattr(path, stbuf, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_getattr: %s -> %d\n", path, blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_create(const char *path, mode_t mode, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->create(path, mode, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_create: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_mkdir(const char *path, mode_t mode)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->mkdir(path, mode);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_mkdir: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_unlink(const char *path)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->unlink(path);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_unlink: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_rmdir(const char *path)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->rmdir(path);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_rmdir: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_rename(const char *path, const char *newname, unsigned int flags)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->rename(path, newname, flags);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_rename: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_truncate(const char *path, off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->truncate(path, offset, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_truncate: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|
off_t offset, struct fuse_file_info *fi,
|
|
enum fuse_readdir_flags flags)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->readdir(path, buf, filler, offset, fi, flags);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_readdir: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_write(const char *path, const char *buf, size_t bufsz, off_t offset,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->write(path, buf, bufsz, offset, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_write: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_open(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->open(path, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_open: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_release(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->release(path, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_release: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
int FuseInterface::f_read(const char *path, char *buf, size_t size, off_t offset,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
int blorg = iface->read(path, buf, size, offset, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_read: %d\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|
|
|
|
off_t FuseInterface::f_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse_context *ctx = fuse_get_context();
|
|
FuseInterface *iface = static_cast<FuseInterface*>(ctx->private_data);
|
|
off_t blorg = iface->lseek(path, off, whence, fi);
|
|
#ifdef FUSE_DEBUG
|
|
fprintf(stderr, "f_lseek: %ld\n", blorg);
|
|
#endif
|
|
return blorg;
|
|
}
|