Add ollie:// KIO worker for Dolphin
Implements a KIO worker that maps ollie:///path to the Ollie 9P namespace. Supports listing, reading, writing, mkdir, delete, and rename — all operations Dolphin needs for full file manager integration. Works with both KF5 (RealWorkerFactory) and KF6 (WorkerFactory). Type ollie:/// in Dolphin's location bar to browse sessions and agents.
This commit is contained in:
parent
739fba2462
commit
18b36c09cd
|
|
@ -46,6 +46,7 @@ if(OLLIE_KF5)
|
||||||
Runner
|
Runner
|
||||||
CoreAddons
|
CoreAddons
|
||||||
Config
|
Config
|
||||||
|
KIO
|
||||||
TextEditor
|
TextEditor
|
||||||
SyntaxHighlighting
|
SyntaxHighlighting
|
||||||
)
|
)
|
||||||
|
|
@ -77,6 +78,25 @@ if(OLLIE_KF5)
|
||||||
$ENV{HOME}/.local/lib/libollie9p.so
|
$ENV{HOME}/.local/lib/libollie9p.so
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- KIO Worker (ollie:// protocol) ---
|
||||||
|
kcoreaddons_add_plugin(kio_ollie SOURCES
|
||||||
|
kio/ollie_kio.cpp
|
||||||
|
gui/lib9pclient.cpp
|
||||||
|
INSTALL_NAMESPACE "kf5/kio"
|
||||||
|
)
|
||||||
|
target_include_directories(kio_ollie PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/gui
|
||||||
|
${CMAKE_SOURCE_DIR}/kio
|
||||||
|
$ENV{HOME}/.local/include
|
||||||
|
)
|
||||||
|
target_link_libraries(kio_ollie
|
||||||
|
KF5::KIOCore
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Network
|
||||||
|
$ENV{HOME}/.local/lib/libollie9p.so
|
||||||
|
)
|
||||||
|
install(FILES kio/ollie.protocol DESTINATION ${KDE_INSTALL_KSERVICESDIR})
|
||||||
|
|
||||||
# --- GUI App (9P-based) ---
|
# --- GUI App (9P-based) ---
|
||||||
# Strip Qt6-only grouped palette syntax (palette.active.*, palette.inactive.*,
|
# Strip Qt6-only grouped palette syntax (palette.active.*, palette.inactive.*,
|
||||||
# palette.disabled.*) — Qt5 QML doesn't support color-group qualifiers.
|
# palette.disabled.*) — Qt5 QML doesn't support color-group qualifiers.
|
||||||
|
|
@ -125,6 +145,7 @@ else()
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Quick QuickControls2 Network)
|
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Quick QuickControls2 Network)
|
||||||
find_package(KF6 REQUIRED COMPONENTS Runner CoreAddons)
|
find_package(KF6 REQUIRED COMPONENTS Runner CoreAddons)
|
||||||
find_package(KF6Config REQUIRED)
|
find_package(KF6Config REQUIRED)
|
||||||
|
find_package(KF6KIO REQUIRED)
|
||||||
|
|
||||||
# KDE's KDE_INSTALL_PLUGINDIR defaults to lib64/plugins/ but Qt6 plugins
|
# KDE's KDE_INSTALL_PLUGINDIR defaults to lib64/plugins/ but Qt6 plugins
|
||||||
# live under lib64/qt6/plugins/. Override so kcoreaddons_add_plugin installs
|
# live under lib64/qt6/plugins/. Override so kcoreaddons_add_plugin installs
|
||||||
|
|
@ -159,6 +180,24 @@ else()
|
||||||
$ENV{HOME}/.local/lib/libollie9p.so
|
$ENV{HOME}/.local/lib/libollie9p.so
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# --- KIO Worker (ollie:// protocol) ---
|
||||||
|
kcoreaddons_add_plugin(kio_ollie SOURCES
|
||||||
|
kio/ollie_kio.cpp
|
||||||
|
gui/lib9pclient.cpp
|
||||||
|
INSTALL_NAMESPACE "kf6/kio"
|
||||||
|
)
|
||||||
|
target_include_directories(kio_ollie PRIVATE
|
||||||
|
${CMAKE_SOURCE_DIR}/gui
|
||||||
|
${CMAKE_SOURCE_DIR}/kio
|
||||||
|
$ENV{HOME}/.local/include
|
||||||
|
)
|
||||||
|
target_link_libraries(kio_ollie
|
||||||
|
KF6::KIOCore
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Network
|
||||||
|
$ENV{HOME}/.local/lib/libollie9p.so
|
||||||
|
)
|
||||||
|
|
||||||
# --- GUI App (9P-based, no D-Bus) ---
|
# --- GUI App (9P-based, no D-Bus) ---
|
||||||
find_package(KF6SyntaxHighlighting REQUIRED)
|
find_package(KF6SyntaxHighlighting REQUIRED)
|
||||||
add_executable(ollie-gui
|
add_executable(ollie-gui
|
||||||
|
|
|
||||||
7
justfile
7
justfile
|
|
@ -56,9 +56,11 @@ uninstall:
|
||||||
rm -f ~/.local/share/applications/org.ollie.gui.desktop
|
rm -f ~/.local/share/applications/org.ollie.gui.desktop
|
||||||
rm -f ~/.local/share/icons/hicolor/scalable/apps/ollie.svg
|
rm -f ~/.local/share/icons/hicolor/scalable/apps/ollie.svg
|
||||||
rm -f ~/.local/lib64/qt6/plugins/kf6/krunner/krunner_ollie.so
|
rm -f ~/.local/lib64/qt6/plugins/kf6/krunner/krunner_ollie.so
|
||||||
rm -f ~/.local/lib64/qt6/plugins/ktexteditor/ollie_kate.so
|
rm -f ~/.local/lib64/qt6/plugins/kf6/ktexteditor/ollie_kate.so
|
||||||
|
rm -f ~/.local/lib64/qt6/plugins/kf6/kio/kio_ollie.so
|
||||||
rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop
|
rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop
|
||||||
rm -f ~/.config/plasma-workspace/env/99-ollie.sh
|
rm -f ~/.config/plasma-workspace/env/99-ollie.sh
|
||||||
|
kbuildsycoca6 --noincremental 2>/dev/null; true
|
||||||
kquitapp6 krunner 2>/dev/null; true
|
kquitapp6 krunner 2>/dev/null; true
|
||||||
@echo '=== KDE uninstall complete ==='
|
@echo '=== KDE uninstall complete ==='
|
||||||
|
|
||||||
|
|
@ -70,7 +72,10 @@ uninstall-kf5:
|
||||||
rm -f ~/.local/share/icons/hicolor/scalable/apps/ollie.svg
|
rm -f ~/.local/share/icons/hicolor/scalable/apps/ollie.svg
|
||||||
rm -f ~/.local/lib/qt5/plugins/kf5/krunner/krunner_ollie.so
|
rm -f ~/.local/lib/qt5/plugins/kf5/krunner/krunner_ollie.so
|
||||||
rm -f ~/.local/lib/qt5/plugins/ktexteditor/ollie_kate.so
|
rm -f ~/.local/lib/qt5/plugins/ktexteditor/ollie_kate.so
|
||||||
|
rm -f ~/.local/lib/qt5/plugins/kf5/kio/kio_ollie.so
|
||||||
rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop
|
rm -f ~/.local/share/kio/servicemenus/ollie-actions.desktop
|
||||||
|
rm -f ~/.local/share/kservices5/ollie.protocol
|
||||||
rm -f ~/.config/plasma-workspace/env/99-ollie-kf5.sh
|
rm -f ~/.config/plasma-workspace/env/99-ollie-kf5.sh
|
||||||
|
kbuildsycoca5 --noincremental 2>/dev/null; true
|
||||||
kquitapp5 krunner 2>/dev/null; true
|
kquitapp5 krunner 2>/dev/null; true
|
||||||
@echo '=== KDE KF5 uninstall complete ==='
|
@echo '=== KDE KF5 uninstall complete ==='
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"KDE-KIO-Protocols": {
|
||||||
|
"ollie": {
|
||||||
|
"Class": ":local",
|
||||||
|
"X-DocPath": "kio_ollie/index.html",
|
||||||
|
"exec": "kio_ollie",
|
||||||
|
"input": "none",
|
||||||
|
"output": "filesystem",
|
||||||
|
"protocol": "ollie",
|
||||||
|
"reading": true,
|
||||||
|
"writing": true,
|
||||||
|
"makedir": true,
|
||||||
|
"deleting": true,
|
||||||
|
"renaming": true,
|
||||||
|
"listing": "Name,Type,Size,Date,Access",
|
||||||
|
"opening": false,
|
||||||
|
"Icon": "ollie",
|
||||||
|
"Description": "Browse the Ollie 9P namespace",
|
||||||
|
"Description[x-test]": "xxBrowse the Ollie 9P namespacexx"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
[Protocol]
|
||||||
|
exec=kio_ollie
|
||||||
|
protocol=ollie
|
||||||
|
input=none
|
||||||
|
output=filesystem
|
||||||
|
reading=true
|
||||||
|
writing=true
|
||||||
|
makedir=true
|
||||||
|
deleting=true
|
||||||
|
renaming=true
|
||||||
|
listing=Name,Type,Size,Date,Access
|
||||||
|
opening=false
|
||||||
|
Icon=ollie
|
||||||
|
Class=:local
|
||||||
|
Description=Browse the Ollie 9P namespace
|
||||||
|
|
@ -0,0 +1,339 @@
|
||||||
|
#include "ollie_kio.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <QMimeType>
|
||||||
|
|
||||||
|
#include <KIO/UDSEntry>
|
||||||
|
#include <KIO/WorkerFactory>
|
||||||
|
|
||||||
|
using namespace KIO;
|
||||||
|
|
||||||
|
// Plugin factory — KIO loads this .so and calls the appropriate create method
|
||||||
|
#if QT_VERSION_MAJOR >= 6
|
||||||
|
class OllieWorkerFactory : public KIO::WorkerFactory
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "org.kde.kio.worker.ollie" FILE "ollie.json")
|
||||||
|
public:
|
||||||
|
using WorkerFactory::WorkerFactory;
|
||||||
|
std::unique_ptr<WorkerBase> createWorker(const QByteArray &pool, const QByteArray &app) override
|
||||||
|
{
|
||||||
|
return std::make_unique<OllieWorker>(pool, app);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
class OllieWorkerFactory : public KIO::RealWorkerFactory
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "org.kde.kio.worker.ollie" FILE "ollie.json")
|
||||||
|
public:
|
||||||
|
using RealWorkerFactory::RealWorkerFactory;
|
||||||
|
std::unique_ptr<SlaveBase> createWorker(const QByteArray &pool, const QByteArray &app) override
|
||||||
|
{
|
||||||
|
Q_UNUSED(pool); Q_UNUSED(app);
|
||||||
|
return nullptr; // unused — KIO calls createRealWorker for RealWorkerFactory
|
||||||
|
}
|
||||||
|
std::unique_ptr<WorkerBase> createRealWorker(const QByteArray &pool, const QByteArray &app) override
|
||||||
|
{
|
||||||
|
return std::make_unique<OllieWorker>(pool, app);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// kdemain entry point — KF5 KIO launches workers by calling this
|
||||||
|
extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QCoreApplication app(argc, argv);
|
||||||
|
app.setApplicationName(QStringLiteral("kio_ollie"));
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
fprintf(stderr, "Usage: kio_ollie protocol pool_socket app_socket\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
OllieWorker worker(argv[2], argv[3]);
|
||||||
|
worker.dispatchLoop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OllieWorker::OllieWorker(const QByteArray &pool, const QByteArray &app)
|
||||||
|
: WorkerBase("ollie", pool, app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OllieWorker::~OllieWorker()
|
||||||
|
{
|
||||||
|
m_client.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OllieWorker::ensureConnected()
|
||||||
|
{
|
||||||
|
if (m_client.isConnected())
|
||||||
|
return true;
|
||||||
|
return m_client.connectDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OllieWorker::ninepPath(const QUrl &url) const
|
||||||
|
{
|
||||||
|
QString path = url.path();
|
||||||
|
// Remove leading slash — 9P root is ""
|
||||||
|
if (path.startsWith(QLatin1Char('/')))
|
||||||
|
path = path.mid(1);
|
||||||
|
// Remove trailing slash
|
||||||
|
if (path.endsWith(QLatin1Char('/')) && path.length() > 1)
|
||||||
|
path.chop(1);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OllieWorker::isDirectory(const QString &mode) const
|
||||||
|
{
|
||||||
|
// 9P mode: starts with 'd' for directory,
|
||||||
|
// or numeric with Plan 9 DMDIR bit (0x80000000)
|
||||||
|
if (mode.startsWith(QLatin1Char('d')))
|
||||||
|
return true;
|
||||||
|
bool ok;
|
||||||
|
uint modeVal = mode.toUInt(&ok, 0);
|
||||||
|
if (ok && (modeVal & 0x80000000))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode_t OllieWorker::parseMode(const QString &modeStr) const
|
||||||
|
{
|
||||||
|
// Try numeric first
|
||||||
|
bool ok;
|
||||||
|
uint modeVal = modeStr.toUInt(&ok, 0);
|
||||||
|
if (ok) {
|
||||||
|
return static_cast<mode_t>(modeVal & 0777);
|
||||||
|
}
|
||||||
|
// Parse rwx string (e.g. "drwxr-xr-x")
|
||||||
|
QString perms = modeStr;
|
||||||
|
if (perms.startsWith(QLatin1Char('d')))
|
||||||
|
perms = perms.mid(1);
|
||||||
|
mode_t m = 0;
|
||||||
|
if (perms.length() >= 9) {
|
||||||
|
if (perms[0] == QLatin1Char('r')) m |= 0400;
|
||||||
|
if (perms[1] == QLatin1Char('w')) m |= 0200;
|
||||||
|
if (perms[2] == QLatin1Char('x')) m |= 0100;
|
||||||
|
if (perms[3] == QLatin1Char('r')) m |= 0040;
|
||||||
|
if (perms[4] == QLatin1Char('w')) m |= 0020;
|
||||||
|
if (perms[5] == QLatin1Char('x')) m |= 0010;
|
||||||
|
if (perms[6] == QLatin1Char('r')) m |= 0004;
|
||||||
|
if (perms[7] == QLatin1Char('w')) m |= 0002;
|
||||||
|
if (perms[8] == QLatin1Char('x')) m |= 0001;
|
||||||
|
} else {
|
||||||
|
m = 0644;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
KIO::UDSEntry OllieWorker::entryFromStat(const QString &path, const QString &name)
|
||||||
|
{
|
||||||
|
UDSEntry entry;
|
||||||
|
auto st = m_client.stat(path);
|
||||||
|
|
||||||
|
if (st.valid) {
|
||||||
|
bool dir = isDirectory(st.mode);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_NAME, name.isEmpty() ? st.name : name);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_SIZE, dir ? 0 : st.size);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_MODIFICATION_TIME, st.mtime);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_ACCESS_TIME, st.mtime);
|
||||||
|
|
||||||
|
mode_t perm = parseMode(st.mode);
|
||||||
|
if (dir) {
|
||||||
|
entry.fastInsert(UDSEntry::UDS_FILE_TYPE, S_IFDIR);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_ACCESS, perm | 0111);
|
||||||
|
} else {
|
||||||
|
entry.fastInsert(UDSEntry::UDS_FILE_TYPE, S_IFREG);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_ACCESS, perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
|
QMimeDatabase db;
|
||||||
|
QMimeType mime = db.mimeTypeForFile(name.isEmpty() ? st.name : name,
|
||||||
|
QMimeDatabase::MatchExtension);
|
||||||
|
if (mime.isValid() && !mime.isDefault()) {
|
||||||
|
entry.fastInsert(UDSEntry::UDS_MIME_TYPE, mime.name());
|
||||||
|
} else {
|
||||||
|
entry.fastInsert(UDSEntry::UDS_MIME_TYPE,
|
||||||
|
QStringLiteral("text/plain"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry.fastInsert(UDSEntry::UDS_NAME, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::listDir(const QUrl &url)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = ninepPath(url);
|
||||||
|
QStringList entries = m_client.ls(path);
|
||||||
|
if (entries.isEmpty() && !m_client.lastError().isEmpty()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_ENTER_DIRECTORY,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit "." entry for the directory itself
|
||||||
|
UDSEntry dot;
|
||||||
|
dot.fastInsert(UDSEntry::UDS_NAME, QStringLiteral("."));
|
||||||
|
dot.fastInsert(UDSEntry::UDS_FILE_TYPE, S_IFDIR);
|
||||||
|
dot.fastInsert(UDSEntry::UDS_ACCESS, 0755);
|
||||||
|
listEntry(dot);
|
||||||
|
|
||||||
|
for (const QString &name : entries) {
|
||||||
|
QString childPath = path.isEmpty() ? name : (path + QLatin1Char('/') + name);
|
||||||
|
UDSEntry entry = entryFromStat(childPath, name);
|
||||||
|
listEntry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::stat(const QUrl &url)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = ninepPath(url);
|
||||||
|
QString name = url.fileName();
|
||||||
|
if (name.isEmpty())
|
||||||
|
name = QStringLiteral(".");
|
||||||
|
|
||||||
|
UDSEntry entry = entryFromStat(path, name);
|
||||||
|
if (!entry.contains(UDSEntry::UDS_FILE_TYPE)) {
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
// Root directory
|
||||||
|
entry.fastInsert(UDSEntry::UDS_NAME, QStringLiteral("."));
|
||||||
|
entry.fastInsert(UDSEntry::UDS_FILE_TYPE, S_IFDIR);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_ACCESS, 0755);
|
||||||
|
entry.fastInsert(UDSEntry::UDS_MIME_TYPE,
|
||||||
|
QStringLiteral("inode/directory"));
|
||||||
|
} else {
|
||||||
|
return WorkerResult::fail(ERR_DOES_NOT_EXIST,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
statEntry(entry);
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::get(const QUrl &url)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = ninepPath(url);
|
||||||
|
QByteArray fileData = m_client.read(path);
|
||||||
|
if (fileData.isNull() && !m_client.lastError().isEmpty()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_READ,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QMimeDatabase db;
|
||||||
|
QMimeType mime = db.mimeTypeForFileNameAndData(url.fileName(), fileData);
|
||||||
|
mimeType(mime.name());
|
||||||
|
|
||||||
|
totalSize(fileData.size());
|
||||||
|
data(fileData);
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::put(const QUrl &url, int /*permissions*/, KIO::JobFlags /*flags*/)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read incoming data from the job
|
||||||
|
QByteArray allData;
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
QByteArray buffer;
|
||||||
|
dataReq();
|
||||||
|
result = readData(buffer);
|
||||||
|
if (result > 0)
|
||||||
|
allData.append(buffer);
|
||||||
|
} while (result > 0);
|
||||||
|
|
||||||
|
QString path = ninepPath(url);
|
||||||
|
if (!m_client.write(path, allData)) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_WRITE,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::mkdir(const QUrl &url, int /*permissions*/)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = ninepPath(url);
|
||||||
|
if (!m_client.mkdir(path)) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_MKDIR,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::del(const QUrl &url, bool /*isFile*/)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path = ninepPath(url);
|
||||||
|
if (!m_client.remove(path)) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_DELETE,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerResult OllieWorker::rename(const QUrl &src, const QUrl &dest, KIO::JobFlags /*flags*/)
|
||||||
|
{
|
||||||
|
if (!ensureConnected()) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_CONNECT,
|
||||||
|
QStringLiteral("Cannot connect to Ollie 9P server: ")
|
||||||
|
+ m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString srcPath = ninepPath(src);
|
||||||
|
QString newName = dest.fileName();
|
||||||
|
if (!m_client.rename(srcPath, newName)) {
|
||||||
|
return WorkerResult::fail(ERR_CANNOT_RENAME,
|
||||||
|
m_client.lastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return WorkerResult::pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "ollie_kio.moc"
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef OLLIE_KIO_H
|
||||||
|
#define OLLIE_KIO_H
|
||||||
|
|
||||||
|
#include <KIO/WorkerBase>
|
||||||
|
#include "lib9pclient.h"
|
||||||
|
|
||||||
|
// KIO worker for ollie:// URLs.
|
||||||
|
// Maps ollie:///path directly to the Ollie 9P namespace.
|
||||||
|
class OllieWorker : public KIO::WorkerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OllieWorker(const QByteArray &pool, const QByteArray &app);
|
||||||
|
~OllieWorker() override;
|
||||||
|
|
||||||
|
KIO::WorkerResult listDir(const QUrl &url) override;
|
||||||
|
KIO::WorkerResult stat(const QUrl &url) override;
|
||||||
|
KIO::WorkerResult get(const QUrl &url) override;
|
||||||
|
KIO::WorkerResult put(const QUrl &url, int permissions, KIO::JobFlags flags) override;
|
||||||
|
KIO::WorkerResult mkdir(const QUrl &url, int permissions) override;
|
||||||
|
KIO::WorkerResult del(const QUrl &url, bool isFile) override;
|
||||||
|
KIO::WorkerResult rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ensureConnected();
|
||||||
|
QString ninepPath(const QUrl &url) const;
|
||||||
|
KIO::UDSEntry entryFromStat(const QString &path, const QString &name);
|
||||||
|
bool isDirectory(const QString &mode) const;
|
||||||
|
mode_t parseMode(const QString &mode) const;
|
||||||
|
|
||||||
|
Lib9pClient m_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OLLIE_KIO_H
|
||||||
Reference in New Issue