quickmod/FuseMounter/fuseinterface.cpp

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;
}