quickmod/FuseMounter/fuseinterface.cpp
Daniel O'Neill 191cd5362a Lots of fixes, VFS now seems to work reliably. Still a lot of cleanup and shoring to do.
Decided to leave the VFS tab for now. Filtering likely doesn't work, except Show Only Open. Sorting works.
Rewrites to replace dynamicRoles done for Mods and Plugins tables.
Database.qml now reads "moddir", though installing extracted is still unimplemented so far.
Launch still doesn't work.
Ignore the "file -> test extract". It's a test for file extraction.
2025-11-10 13:15:26 -08:00

969 lines
27 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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>
#include <QSqlError>
#include <QSqlQuery>
#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);
free(fbuf.mem);
} 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);
readDeleted();
m_mutex.unlock();
}
void FuseInterface::clear()
{
m_mutex.lock();
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
{
fab->deleteLater();
}
m_accessors.clear();
m_deleted.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;
}
*/
/*
* In FUSE3, the kernel treats fuse_file_info.fh as opaque state owned by the userspace daemon, but its
* copied once at open time into the kernels internal struct file. After that, every subsequent operation
* (read/write/release/etc.) gets a copy of that fh value from the kernel, not a live reference back into
* userspace memory.
*/
FuseFHBase *FuseInterface::getFH(struct fuse_file_info *fi)
{
if( m_cow_redirects.contains(fi->fh) )
return m_cow_redirects.value(fi->fh);
return reinterpret_cast<FuseFHBase *>(fi->fh);
}
FuseFHBase *FuseInterface::makeWritableFromSource(fuse_file_info *fi, 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_cow_redirects.insert(fi->fh, fh);
cacheInvalidate(dest);
m_mutex.unlock();
return fh;
}
m_mutex.unlock();
return NULL;
}
FuseFHBase *FuseInterface::makeWritableFromData(struct fuse_file_info *fi, 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_cow_redirects.insert(fi->fh, fh);
cacheInvalidate(dest);
m_mutex.unlock();
return fh;
}
m_mutex.unlock();
qDebug() << "FuseInterface::makeWritableFromData: Couldn't do it.";
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(FuseAccessorBase *fab, const QString &path, const QByteArray &data)
{
if (data.isEmpty())
return;
QString qpath(path.toLower());
auto val = QSharedPointer<QByteArray>::create(data);
m_cache_data.insert(qpath, new QSharedPointer<QByteArray>(std::move(val)), val->size());
qDebug() << " - m_cache_data now contains" << m_cache_data.size() << "entries, totalling" << humanSize(m_cache_data.totalCost()) << "bytes";
emit entryUpdated(qpath, fab->getType(), fab->getResource(), 1, 1);
}
QSharedPointer<QByteArray> FuseInterface::cacheGrab(const QString &path)
{
if (auto ptr = m_cache_data.object(path.toLower()))
return *ptr;
return {};
}
/*
void FuseInterface::cacheInsert(FuseAccessorBase *fab, const QString &path, const QByteArray &data)
{
if( data.isEmpty() )
return;
QString qpath(path.toLower());
//QSharedPointer<QByteArray> val = QSharedPointer<QByteArray>::create(data);
//m_cache_data.insert(qpath, new QSharedPointer<QByteArray>(val), val->size());
m_cache_data.insert(qpath, new QByteArray(data), data.size());
qDebug() << " - m_cache_data now contains" << m_cache_data.size() << "entries, totalling" << humanSize(m_cache_data.totalCost()) << "bytes";
emit entryUpdated(qpath, fab->getType(), fab->getResource(), 1, 1);
}
QByteArray FuseInterface::cacheGrab(const QString &path)
{
QString qpath(path.toLower());
if( !m_cache_data.contains(qpath) )
return {};
auto *data = m_cache_data.object(qpath);
return data ? *data : QByteArray();
}
*/
void FuseInterface::cacheInvalidate(const QString &path)
{
QString qpath = path.toLower();
//qDebug() << "FuseInterface::cacheInvalidate:" << path;
if( m_cache_data.contains(qpath) )
m_cache_data.remove(qpath);
if( m_dircache.contains(qpath) )
m_dircache.remove(qpath);
if( m_cache_stat.contains(qpath) ) {
struct stat *st = m_cache_stat.take(qpath);
free(st);
}
if( m_cache_accessor.contains(qpath) )
m_cache_accessor.remove(qpath);
}
bool FuseInterface::markDeleted(const QString &path, bool isdeleted)
{
if( isdeleted )
m_deleted.append(path.toLower());
else
m_deleted.removeAll(path.toLower());
QString qstr = QString("REPLACE INTO proxyOverrides(path, deleted)VALUES(?, %1)").arg(isdeleted ? 1 : 0);
qDebug() << qstr << path;
QSqlQuery q = QSqlQuery(qstr, m_database);
q.bindValue(0, path);
bool ret = q.exec();
if( !ret )
qDebug() << m_database.lastError();
return ret;
}
void FuseInterface::readDeleted()
{
m_deleted.clear();
QString qstr = QString("SELECT path, deleted FROM proxyOverrides WHERE deleted=1");
qDebug() << qstr;
QSqlQuery q = QSqlQuery(qstr, m_database);
while( q.next() )
{
QString path = q.value(0).toString();
m_deleted.append(path.toLower());
}
}
int FuseInterface::getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
{
Q_UNUSED(fi)
int ret;
QString qpath(path);
QString lpath = qpath.toLower();
if( m_deleted.contains(lpath) )
return -ENOENT;
if( CACHE_ENABLED && m_cache_stat.contains(lpath) )
{
if( !m_cache_stat[lpath] )
return -ENOENT;
memcpy( stbuf, m_cache_stat[lpath], 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(lpath, scache);
//m_cache_accessor.insert(qpath, ent);
return 0;
}
}
m_cache_stat.insert(lpath, 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 )
cacheInvalidate(qpath);
m_mutex.unlock();
if( 0 == ret && sb ) {
if( m_deleted.contains(qpath.toLower()) )
markDeleted(qpath, false);
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 )
cacheInvalidate(qpath);
if( 0 == ret && m_deleted.contains(qpath.toLower()) )
markDeleted(qpath, false);
m_mutex.unlock();
return ret;
}
int FuseInterface::unlink(const char *path)
{
bool isFound = false;
int ret = -ENOENT;
QString qpath(path);
struct stat st;
m_mutex.lock();
for( FuseAccessorBase *fab : std::as_const(m_accessors) )
{
int sret = fab->getattr(qpath, &st);
if( 0 == sret )
isFound = true;
else
continue;
if( FuseAccessorBase::FH_SANDBOX != fab->getType() )
continue;
FuseAccessorSandbox *sb = qobject_cast<FuseAccessorSandbox *>(fab);
ret = sb->unlink(qpath);
break;
}
if( CACHE_ENABLED )
cacheInvalidate(qpath);
if( isFound ) {
markDeleted(qpath, true);
ret = 0;
}
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 )
cacheInvalidate(qpath);
if( 0 == ret )
markDeleted(qpath, true);
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 )
cacheInvalidate(qpath);
if( 0 == ret && m_deleted.contains(qpath.toLower()) )
markDeleted(qpath, false);
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);
QString lpath = qpath.toLower();
if( CACHE_ENABLED && m_dircache.contains(lpath) )
{
QStringList ents = m_dircache[lpath];
for( const QString &ent : std::as_const(ents) ) {
QString qipath = QString("%1/%2").arg(qpath).arg(ent);
if( m_deleted.contains(qipath.toLower()) )
continue;
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 qipath = QString("%1/%2").arg(qpath).arg(nent);
if( m_deleted.contains(qipath.toLower()) )
continue;
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[lpath] = ents;
return 0;
}
int FuseInterface::write(const char *path, const char *buf, size_t bufsz, off_t offset, struct fuse_file_info *fi)
{
QString qpath(path);
FuseFHBase *fhbase = getFH(fi);
//qDebug() << "FuseInterface::write:" << fi << fhbase << path;
//FuseAccessorBase *fabase = fhbase->getAccessor();
/*
qDebug() << "fabase:" << fabase;
qDebug() << "Type:" << fabase->getType();
*/
FuseFHBase *sfh = qobject_cast<FuseFHBase *>(fhbase);
QByteArray data(buf, bufsz);
if( CACHE_ENABLED )
cacheInvalidate(qpath);
return sfh->write(data, offset, fi);
}
int FuseInterface::open(const char *path, struct fuse_file_info *fi)
{
bool checkDeleted = false;
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;
checkDeleted = true;
}
if( !( O_CREAT & fi->flags ) ) {
qmode |= QIODeviceBase::ExistingOnly;
checkDeleted = true;
}
if( checkDeleted && m_deleted.contains(qpath.toLower()) )
return -ENOENT;
// STATS:
VFSStatEntry se { qpath, QDateTime::currentSecsSinceEpoch(), 0, 0, 1 };
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.toLower(), fab->getType(), fh->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 << fh << qmode;
m_stats.insert(qpath, se);
}
m_stats[qpath].openCount++;
m_stats[qpath].refCount++;
emit entryUpdated(qpath.toLower(), fab->getType(), fh->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)
m_mutex.lock();
FuseFHBase *fhbase = getFH(fi);
qDebug() << "FuseInterface::release:" << fi << fhbase << path;
QString qpath = fhbase->getPath();
VFSStatEntry se { qpath, QDateTime::currentSecsSinceEpoch(), 0, 0, 1 };
if( !m_stats.contains(qpath) )
qDebug() << "Warning:" << qpath << "release, wasn't opened. Name was changed?";
else {
m_stats[qpath].refCount--;
emit entryUpdated(qpath.toLower(), fhbase->getAccessor()->getType(), fhbase->getResource(), m_stats[qpath].openCount, m_stats[qpath].refCount);
}
m_open_handles.removeOne(fhbase);
fhbase->release();
fhbase->deleteLater();
if( m_cow_redirects.contains(fi->fh))
m_cow_redirects.remove(fi->fh);
m_mutex.unlock();
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 = getFH(fi);
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 = getFH(fi);
//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;
}