690 lines
19 KiB
C++
690 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;
|
|
}
|
|
|
|
#ifndef FUSE_FILL_DIR_DEFAULTS
|
|
# define FUSE_FILL_DIR_DEFAULTS (enum fuse_fill_dir_flags)0
|
|
#endif
|
|
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_DEFAULTS);
|
|
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_DEFAULTS);
|
|
}
|
|
|
|
/* 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());
|
|
/* FIXME: We need to make the "created" a format override, check that first, then arcs, extracted, then vanilla.
|
|
* !!!!!!!!!!!!!
|
|
*
|
|
QByteArray *src = archive->getEntry(mod->m_archivePath);
|
|
QFile f(qpath);
|
|
f.open(QIODeviceBase::WriteOnly);
|
|
f.write(*src);
|
|
f.close();
|
|
*/
|
|
|
|
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);
|
|
}
|