Updated QML and C++ in various places to build and work with new Qt (6.4+) Minor bugfixes, possibly caused by the Qt version bump, and mostly in JS logic. Tried (again) to get mod sorting working by dragging them within the list. Initial support for Profiles. (To switch between FO4 and FOLON, for example.) Initial "Launch Game" stuff, but it's far from done. Don't use it (yet).
678 lines
19 KiB
C++
678 lines
19 KiB
C++
#include "fusestuff.h"
|
|
#include "archivemanager.h"
|
|
#include "database.h"
|
|
#include "fsproxy.h"
|
|
#include "database.h"
|
|
|
|
#include <QDir>
|
|
#include <QSocketNotifier>
|
|
#include <QDateTime>
|
|
|
|
extern "C" {
|
|
#define FUSE_USE_VERSION 31
|
|
|
|
#include <fuse3/fuse.h>
|
|
#include <fuse3/fuse_lowlevel.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
}
|
|
|
|
static FILE *logfd = NULL;
|
|
QMap< QString, QStringList > g_dircache;
|
|
QMap<QString, struct stat *> g_shortcuts;
|
|
QSocketNotifier *g_notifier;
|
|
|
|
void dolog(const char *fmt, ...)
|
|
{
|
|
//return;
|
|
|
|
char ostr[8192];
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(ostr, sizeof(ostr), fmt, ap);
|
|
va_end(ap);
|
|
|
|
QDateTime now = QDateTime::currentDateTime();
|
|
QString tstr = now.toString(Qt::ISODateWithMs);
|
|
QString dstamp = QString("[%1] ").arg( tstr );
|
|
|
|
fwrite(dstamp.toStdString().c_str(), dstamp.length(), 1, stdout);
|
|
fwrite(dstamp.toStdString().c_str(), dstamp.length(), 1, logfd);
|
|
fwrite(ostr, strlen(ostr), 1, stdout);
|
|
fwrite(ostr, strlen(ostr), 1, logfd);
|
|
fflush(logfd);
|
|
}
|
|
|
|
static QString cleanup_path(const char *path)
|
|
{
|
|
QString result = QString(path+1).replace("//", "/");
|
|
return result;
|
|
}
|
|
|
|
static ArchiveManager *g_archive = NULL;
|
|
void qmfuse_set_archive(ArchiveManager *archive)
|
|
{
|
|
g_archive = archive;
|
|
}
|
|
|
|
static FSProxy *g_proxy = NULL;
|
|
void qmfuse_set_proxy(FSProxy *proxy)
|
|
{
|
|
g_proxy = proxy;
|
|
}
|
|
|
|
static Database *g_database = NULL;
|
|
void qmfuse_set_database(Database *db)
|
|
{
|
|
g_database = db;
|
|
}
|
|
|
|
void qmfuse_reset()
|
|
{
|
|
QList< struct stat * > gsvals = g_shortcuts.values();
|
|
g_dircache.clear();
|
|
g_shortcuts.clear();
|
|
for( struct stat *st : gsvals )
|
|
delete st;
|
|
}
|
|
|
|
static bool qmfuse_dircache_remove(const QString &qpath)
|
|
{
|
|
QStringList parts = qpath.split(QDir::separator());
|
|
parts.takeLast();
|
|
QString npath = parts.join(QDir::separator());
|
|
if( !g_dircache.contains(npath) )
|
|
return false;
|
|
g_dircache.remove(npath);
|
|
return true;
|
|
}
|
|
|
|
static void *qmfuse_init(struct fuse_conn_info *conn,
|
|
struct fuse_config *cfg)
|
|
{
|
|
(void) conn;
|
|
cfg->kernel_cache = 0;
|
|
|
|
logfd = fopen("/tmp/quickmod.txt", "w");
|
|
return NULL;
|
|
}
|
|
|
|
static int qmfuse_getattr(const char *path, struct stat *stbuf,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(fi)
|
|
QString spath = path;
|
|
if( g_shortcuts.contains(spath) )
|
|
{
|
|
if( NULL == g_shortcuts[spath] ) {
|
|
//dolog("getattr: already know %s doesn't exist!\n", path);
|
|
return -ENOENT;
|
|
} else {
|
|
struct stat *st = g_shortcuts[spath];
|
|
memcpy( stbuf, st, sizeof(struct stat));
|
|
return 0;
|
|
}
|
|
}
|
|
dolog("getattr: %s\n", path);
|
|
|
|
QString qpath = cleanup_path(path);
|
|
memset(stbuf, 0, sizeof(struct stat));
|
|
|
|
QStringList qparts = qpath.split(QDir::separator());
|
|
if( 0 == qpath.length() )
|
|
qparts.clear();
|
|
/*
|
|
if( qpath.endsWith(".ciopfs") )
|
|
{
|
|
stbuf->st_mode = S_IFREG | 0755;
|
|
stbuf->st_nlink = 1;
|
|
stbuf->st_uid = geteuid();
|
|
stbuf->st_gid = getegid();
|
|
return 0;
|
|
}
|
|
*/
|
|
if( g_database->isProxyOverride(qpath.toLower()) )
|
|
{
|
|
dolog("getattr(1): override exists for %s!\n", path+1);
|
|
if( g_proxy->getattr(qpath, stbuf) )
|
|
return 0;
|
|
}
|
|
|
|
/* First the mods: */
|
|
ModLibrary *library;
|
|
ModEntry *mod;
|
|
Archive *archive;
|
|
if( g_archive->findFile(qpath, &library, &mod, &archive) )
|
|
{
|
|
if( !mod ) {
|
|
dolog("getattr(4): returning that we're a directory\n");
|
|
stbuf->st_mode = S_IFDIR | 0755;
|
|
stbuf->st_nlink = 2;
|
|
stbuf->st_uid = geteuid();
|
|
stbuf->st_gid = getegid();
|
|
time_t t = time(NULL);
|
|
stbuf->st_atim.tv_sec = t;
|
|
stbuf->st_ctim.tv_sec = t;
|
|
stbuf->st_mtim.tv_sec = t;
|
|
struct stat *st = new struct stat;
|
|
memcpy(st, stbuf, sizeof(struct stat));
|
|
g_shortcuts[spath] = st;
|
|
return 0;
|
|
}
|
|
|
|
if( !archive ) {
|
|
dolog("getattr(4): No archive entry for \"%s\"!\n", qpath.toStdString().c_str());
|
|
return -ENOENT;
|
|
}
|
|
|
|
ArchiveCacheEntry *cacheEntry = archive->cache(mod->m_archivePath);
|
|
if( !cacheEntry )
|
|
{
|
|
dolog("getattr(4): No cache entry for \"%s\"!\n", qpath.toStdString().c_str());
|
|
return -ENOENT;
|
|
}
|
|
|
|
memcpy( stbuf, &cacheEntry->m_stat, sizeof(struct stat) );
|
|
stbuf->st_uid = geteuid();
|
|
stbuf->st_gid = getegid();
|
|
struct stat *st = new struct stat;
|
|
memcpy(st, stbuf, sizeof(struct stat));
|
|
g_shortcuts[spath] = st;
|
|
|
|
dolog("getattr(4): returning that we're a file (\"%s\" => \"%s\")\n",
|
|
mod->m_archivePath.toLower().toStdString().c_str(), mod->m_installedPath.toStdString().c_str() );
|
|
return 0;
|
|
}
|
|
|
|
/* Now check overlay (after): */
|
|
if( g_proxy->getattr(qpath, stbuf) )
|
|
return 0;
|
|
|
|
dolog("getattr (4xxx): !!! Couldn't find \"%s\" anywhere in our libraries!\n", path+1);
|
|
g_shortcuts[spath] = NULL;
|
|
return -ENOENT;
|
|
}
|
|
|
|
static int qmfuse_mknod(const char *path, mode_t mode, dev_t dev)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("mknod: \"%s\" %d %d\n", qpath.toStdString().c_str(), mode, dev);
|
|
int ret = g_proxy->mknod(qpath, mode, dev);
|
|
g_shortcuts.remove(QString(path));
|
|
qmfuse_dircache_remove(qpath);
|
|
return ret;
|
|
}
|
|
|
|
static int qmfuse_mkdir(const char *path, mode_t mode)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("mkdir: %s\n", qpath.toStdString().c_str());
|
|
g_shortcuts.remove(QString(path));
|
|
qmfuse_dircache_remove(qpath);
|
|
return g_proxy->mkdir(qpath, mode);
|
|
}
|
|
|
|
static int qmfuse_unlink(const char *path)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("unlink: %s\n", qpath.toStdString().c_str());
|
|
g_shortcuts.remove(QString(path));
|
|
qmfuse_dircache_remove(qpath);
|
|
g_database->unregisterProxyOverride(qpath);
|
|
return g_proxy->unlink(qpath.toStdString().c_str());
|
|
}
|
|
|
|
static int qmfuse_rmdir(const char *path)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("rmdir: %s\n", qpath.toStdString().c_str());
|
|
g_shortcuts.remove(QString(path));
|
|
qmfuse_dircache_remove(qpath);
|
|
return g_proxy->rmdir(qpath);
|
|
}
|
|
|
|
static int qmfuse_rename(const char *path, const char *newname, unsigned int flags)
|
|
{
|
|
QString qpathA = cleanup_path(path);
|
|
QString qpathB = cleanup_path(newname);
|
|
dolog("rename: %s => %s\n",
|
|
qpathA.toStdString().c_str(),
|
|
qpathB.toStdString().c_str()
|
|
);
|
|
g_shortcuts.remove(QString(path));
|
|
g_shortcuts.remove(QString(newname));
|
|
qmfuse_dircache_remove(qpathA);
|
|
qmfuse_dircache_remove(qpathB);
|
|
return g_proxy->rename(qpathA, qpathB, flags);
|
|
}
|
|
|
|
static int qmfuse_truncate(const char *path, off_t offset, struct fuse_file_info *fi)
|
|
{
|
|
Q_UNUSED(fi);
|
|
QString qpath = cleanup_path(path);
|
|
dolog("truncate: %s\n", qpath.toStdString().c_str());
|
|
int ret = g_proxy->truncate(qpath, offset);
|
|
g_shortcuts.remove(QString(path));
|
|
qmfuse_dircache_remove(qpath);
|
|
return ret;
|
|
}
|
|
|
|
static int qmfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|
off_t offset, struct fuse_file_info *fi,
|
|
enum fuse_readdir_flags flags)
|
|
{
|
|
(void) offset;
|
|
(void) fi;
|
|
(void) flags;
|
|
|
|
QString qpath = cleanup_path(path);
|
|
if( g_dircache.contains(qpath) )
|
|
{
|
|
QStringList ents = g_dircache[qpath];
|
|
for( const QString &e : ents )
|
|
filler(buf, e.toStdString().c_str(), NULL, 0, FUSE_FILL_DIR_PLUS);
|
|
return 0;
|
|
}
|
|
|
|
dolog("readdir: %s\n", qpath.toStdString().c_str());
|
|
QStringList filesshared;
|
|
|
|
/* First the overlay: */
|
|
QStringList proxyentries = g_proxy->readdir(qpath);
|
|
for( const QString &ent : proxyentries )
|
|
{
|
|
QStringList parts = ent.split(QDir::separator());
|
|
QString nent = parts.last();
|
|
//dolog("readdir(3): proxy: %s\n", nent.toStdString().c_str());
|
|
filesshared.append(nent);
|
|
filler(buf, nent.toStdString().c_str(), NULL, 0, FUSE_FILL_DIR_PLUS);
|
|
}
|
|
|
|
/* Now the mods: */
|
|
QStringList qparts = qpath.split(QDir::separator());
|
|
if( 0 == qpath.length() )
|
|
qparts.clear();
|
|
|
|
QHash< ModLibrary *, Archive * > entries = g_archive->getArchives();
|
|
const QList< ModLibrary * > &ekeys = entries.keys();
|
|
for( ModLibrary *library : ekeys )
|
|
{
|
|
//QMap<QString, ArchiveCacheEntry> arc = entries[library].getEntries();
|
|
for( ModEntry *mod : library->m_entries )
|
|
{
|
|
/*
|
|
dolog("readdir(2): \"%s\" startsWith \"%s\"?\n",
|
|
mod.m_installedPath.toStdString().c_str(),
|
|
qpath.toStdString().c_str());
|
|
*/
|
|
QStringList parts = mod->m_installedPath.split(QDir::separator());
|
|
/*
|
|
dolog("readdir(4): Comparing: qpath=\"%s\" vs. path=\"%s\"...\n",
|
|
qparts.join(QDir::separator()).toStdString().c_str(),
|
|
parts.join(QDir::separator()).toStdString().c_str()
|
|
);
|
|
*/
|
|
if( parts.length() <= qparts.length() )
|
|
continue;
|
|
|
|
bool skipme = false;
|
|
for( int x=0; x < qparts.length(); x++ )
|
|
{
|
|
if( 0 == parts.at(x).length() )
|
|
continue;
|
|
|
|
if( 0 == qparts.at(x).length() )
|
|
continue;
|
|
|
|
if( 0 != qparts.at(x).compare(parts.at(x), Qt::CaseInsensitive) )
|
|
{
|
|
skipme = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( skipme )
|
|
continue;
|
|
|
|
QString target = parts.at(qparts.length());
|
|
if( filesshared.contains(target, Qt::CaseInsensitive) )
|
|
continue;
|
|
|
|
//dolog("readdir(4b): \"%s\" => \"%s\"\n", mod.m_installedPath.toStdString().c_str(), qpath.toStdString().c_str());
|
|
filesshared.append(target);
|
|
filler(buf, target.toStdString().c_str(), NULL, 0, FUSE_FILL_DIR_PLUS);
|
|
}
|
|
}
|
|
|
|
g_dircache[qpath] = filesshared;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int qmfuse_write(const char *path, const char *buf, size_t bufsz, off_t offset,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("write: \"%s\" %d bytes, %d offset\n", qpath.toStdString().c_str(), bufsz, offset);
|
|
int ret = g_proxy->write(fi->fh, buf, bufsz, offset);
|
|
//if( g_shortcuts.contains(qpath) )
|
|
g_shortcuts.remove(QString(path));
|
|
qmfuse_dircache_remove(qpath);
|
|
return ret;
|
|
}
|
|
|
|
static int qmfuse_open(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("open: %s\n", qpath.toStdString().c_str());
|
|
|
|
if( g_database->isProxyOverride(qpath.toLower()) )
|
|
{
|
|
dolog("open(1): override exists for %s!\n", qpath.toStdString().c_str());
|
|
int fd = g_proxy->open(qpath);
|
|
if( fd > 0 ) {
|
|
fi->fh = fd;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* First the mods: */
|
|
ModLibrary *library;
|
|
ModEntry *mod;
|
|
Archive *archive;
|
|
if( g_archive->findFile(qpath, &library, &mod, &archive) )
|
|
{
|
|
if( !archive ) {
|
|
dolog("open(1): attempt to open a directory? iunno: %s\n", qpath.toStdString().c_str());
|
|
return -EINVAL;
|
|
}
|
|
/*
|
|
if( !archive->contains(mod->m_archivePath) )
|
|
{
|
|
dolog("open(3): Archive does not contain \"%s\"!\n", qpath.toStdString().c_str());
|
|
return -ENOENT;
|
|
}
|
|
*/
|
|
|
|
int fam = (fi->flags & O_ACCMODE);
|
|
if( fam == O_RDWR || fam == O_WRONLY )
|
|
{
|
|
// Make a proxy override...
|
|
dolog("open(2): trying to open for write: %s\n", qpath.toStdString().c_str());
|
|
int fd = g_proxy->open(qpath, true);
|
|
if( fd <= 0 ) {
|
|
dolog("open(2): no dice, for some reason.\n");
|
|
return -EACCES;
|
|
}
|
|
|
|
g_database->registerProxyOverride(qpath.toLower());
|
|
g_shortcuts.remove(qpath);
|
|
fi->fh = fd;
|
|
return 0;
|
|
}
|
|
|
|
dolog("open(2): opened \"%s\"\n", mod->m_installedPath.toStdString().c_str());
|
|
fi->fh = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* Now check overlay (after): */
|
|
int fd = g_proxy->open(qpath);
|
|
if( fd > 0 ) {
|
|
fi->fh = fd;
|
|
return 0;
|
|
}
|
|
|
|
if( fi->flags & O_CREAT ) {
|
|
fd = g_proxy->open(qpath, true);
|
|
g_shortcuts.remove(qpath);
|
|
fi->fh = fd;
|
|
return 0;
|
|
}
|
|
|
|
return -EACCES;
|
|
}
|
|
|
|
static int qmfuse_release(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
dolog("release: %s\n", qpath.toStdString().c_str());
|
|
if( fi->fh <= 0 ) {
|
|
//g_archive->cleanCache();
|
|
return 0;
|
|
}
|
|
|
|
g_proxy->close(fi->fh);
|
|
return 0;
|
|
}
|
|
|
|
static int qmfuse_read(const char *path, char *buf, size_t size, off_t offset,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
QString qpath = cleanup_path(path);
|
|
|
|
/* check overlay: */
|
|
if( fi->fh > 0 ) {
|
|
int ret = g_proxy->read(fi->fh, buf, size, offset);
|
|
//if( ret != -EACCES )
|
|
return ret;
|
|
}
|
|
|
|
/* mods after: */
|
|
ModLibrary *library;
|
|
ModEntry *mod;
|
|
Archive *archive;
|
|
if( g_archive->findFile(qpath, &library, &mod, &archive) )
|
|
{
|
|
/*
|
|
if( !archive->contains(mod->m_archivePath) )
|
|
{
|
|
dolog("read(3): Archive does not contain \"%s\"!\n", qpath.toStdString().c_str());
|
|
return -ENOENT;
|
|
}
|
|
*/
|
|
if( !archive ) {
|
|
dolog("open(1): attempt to read a directory? iunno: %s\n", qpath.toStdString().c_str());
|
|
return -EINVAL;
|
|
}
|
|
|
|
ArchiveCacheEntry *cacheEntry = archive->cache(mod->m_archivePath);
|
|
if( cacheEntry && cacheEntry->m_loading ) {
|
|
qDebug() << QString("getEntry(%1) -> (Still Loading...)\n").arg(qpath);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
QByteArray *src = archive->getEntry(mod->m_archivePath);
|
|
if( !src || 0 == src->length() )
|
|
{
|
|
dolog("read(2): got 0-byte length while trying to read \"%s\"\n", qpath.toStdString().c_str());
|
|
return 0;
|
|
}
|
|
|
|
if( offset >= src->length() )
|
|
{
|
|
archive->releaseEntry(mod->m_archivePath);
|
|
return -EOF;
|
|
}
|
|
|
|
if (offset + size > (size_t)src->length())
|
|
size = src->length() - offset;
|
|
if( size > 0 )
|
|
memcpy(buf, src->constData() + offset, size);
|
|
int ret = size;
|
|
if( ret < 0 )
|
|
ret = 0;
|
|
archive->releaseEntry(mod->m_archivePath);
|
|
return ret;
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|
|
|
|
static off_t qmfuse_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
|
|
{
|
|
/* check overlay: */
|
|
if( fi->fh > 0 ) {
|
|
int ret = g_proxy->lseek(fi->fh, off, whence);
|
|
if( -EINVAL == ret )
|
|
dolog("lseek(1): g_proxy->lseek on fd resulted in -EINVAL (whence is %d)\n", whence);
|
|
return ret;
|
|
}
|
|
|
|
QString qpath = cleanup_path(path);
|
|
|
|
/* mods after: */
|
|
ModLibrary *library;
|
|
ModEntry *mod;
|
|
Archive *archive;
|
|
if( g_archive->findFile(qpath, &library, &mod, &archive) )
|
|
{
|
|
if( !archive )
|
|
//if( !archive->contains(qpath) )
|
|
{
|
|
dolog("lseek(3): Archive does not contain \"%s\"!\n", qpath.toStdString().c_str());
|
|
return -ENOENT;
|
|
}
|
|
|
|
ArchiveCacheEntry *cacheEntry = archive->cache(mod->m_archivePath);
|
|
if( cacheEntry && cacheEntry->m_loading ) {
|
|
qDebug() << QString("getEntry(%1) -> (Still Loading...)\n").arg(qpath);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
if( SEEK_SET != whence )
|
|
return -EINVAL;
|
|
return off;
|
|
/*
|
|
if( cacheEntry->m_data.length() >= off )
|
|
return off;
|
|
return -EACCES;
|
|
*/
|
|
}
|
|
|
|
dolog("lseek: %s\n", path+1);
|
|
return g_proxy->lseek(fi->fh, off, whence);
|
|
}
|
|
|
|
|
|
static const struct fuse_operations qmfuse_oper = {
|
|
.getattr = qmfuse_getattr,
|
|
.readlink = NULL,
|
|
.mknod = qmfuse_mknod,
|
|
.mkdir = qmfuse_mkdir,
|
|
.unlink = qmfuse_unlink,
|
|
.rmdir = qmfuse_rmdir,
|
|
.symlink = NULL,
|
|
.rename = qmfuse_rename,
|
|
.link = NULL,
|
|
.chmod = NULL,
|
|
.chown = NULL,
|
|
.truncate = qmfuse_truncate,
|
|
.open = qmfuse_open,
|
|
.read = qmfuse_read,
|
|
.write = qmfuse_write,
|
|
.statfs = NULL,
|
|
.flush = NULL,
|
|
.release = qmfuse_release,
|
|
.fsync = NULL,
|
|
.setxattr = NULL,
|
|
.getxattr = NULL,
|
|
.listxattr = NULL,
|
|
.removexattr = NULL,
|
|
.opendir = NULL,
|
|
.readdir = qmfuse_readdir,
|
|
.releasedir = NULL,
|
|
.fsyncdir = NULL,
|
|
.init = qmfuse_init,
|
|
.destroy = NULL,
|
|
.access = NULL,
|
|
.create = NULL,
|
|
.lock = NULL,
|
|
.utimens = NULL,
|
|
.bmap = NULL,
|
|
.ioctl = NULL,
|
|
.poll = NULL,
|
|
.write_buf = NULL,
|
|
.read_buf = NULL,
|
|
.flock = NULL,
|
|
.fallocate = NULL,
|
|
.copy_file_range = NULL,
|
|
.lseek = qmfuse_lseek,
|
|
};
|
|
|
|
struct fuse *g_fuse;
|
|
struct fuse_session *g_fuse_session;
|
|
int qmfuse_main(const char *mountpoint)
|
|
{
|
|
/*
|
|
char *argv[4];
|
|
argv[0] = "quickmod";
|
|
argv[1] = (char*)mountpoint;
|
|
argv[2] = "-f";
|
|
argv[3] = "-s";
|
|
return fuse_main(3, argv, &qmfuse_oper, NULL);
|
|
*/
|
|
|
|
char *argv[4];
|
|
argv[0] = "quickmod";
|
|
argv[1] = (char*)mountpoint;
|
|
argv[2] = "-f";
|
|
//argv[3] = "-s";
|
|
//int argc = sizeof(*argv) / sizeof(argv[0]);
|
|
//struct fuse_args args = FUSE_ARGS_INIT(4, argv);
|
|
struct fuse_args args = FUSE_ARGS_INIT(3, argv);
|
|
struct fuse_cmdline_opts opts;
|
|
|
|
if( 0 != fuse_parse_cmdline(&args, &opts) ) {
|
|
fprintf(stderr, "Failed to parse options.\n");
|
|
return -1;
|
|
}
|
|
|
|
size_t op_size = sizeof(*(&qmfuse_oper));
|
|
g_fuse = fuse_new(&args, &qmfuse_oper, op_size, NULL);
|
|
if( !g_fuse ) {
|
|
fprintf(stderr, "Failed to create new FUSE object.\n");
|
|
return -2;
|
|
}
|
|
|
|
if( 0 != fuse_mount(g_fuse, mountpoint) ) {
|
|
fprintf(stderr, "Failed at fuse_mount!\n");
|
|
return -3;
|
|
}
|
|
|
|
g_fuse_session = fuse_get_session(g_fuse);
|
|
if( 0 != fuse_set_signal_handlers(g_fuse_session) ) {
|
|
fprintf(stderr, "Failed to set FUSE signal handlers!\n");
|
|
return -4;
|
|
}
|
|
|
|
//g_notifier = new QSocketNotifier(fuse_session_fd(g_fuse_session), QSocketNotifier::Read);
|
|
return fuse_session_fd(g_fuse_session);
|
|
}
|
|
|
|
int qmfuse_pump()
|
|
{
|
|
struct fuse_buf fbuf = { .mem = NULL };
|
|
if( fuse_session_exited(g_fuse_session) ) {
|
|
fprintf(stderr, "Feh. Session closed!\n");
|
|
return -1;
|
|
}
|
|
|
|
int res = fuse_session_receive_buf(g_fuse_session, &fbuf);
|
|
if( -EINTR == res )
|
|
return 0; // Nothing to do.
|
|
|
|
if( 0 >= res )
|
|
return res;
|
|
|
|
fuse_session_process_buf(g_fuse_session, &fbuf);
|
|
return 0;
|
|
}
|
|
|
|
void qmfuse_unmount()
|
|
{
|
|
fuse_session_unmount(g_fuse_session);
|
|
}
|