Skip to content

Commit 3c1d118

Browse files
committed
Return XAttr vfs plugin for Linux and Mac
1 parent ec9f5c5 commit 3c1d118

File tree

11 files changed

+190
-189
lines changed

11 files changed

+190
-189
lines changed

src/gui/folderwizard/folderwizard.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,12 @@ const AccountStatePtr &FolderWizardPrivate::accountState()
121121

122122
bool FolderWizardPrivate::useVirtualFiles() const
123123
{
124+
#ifdef Q_OS_WIN
124125
return VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::WindowsCfApi;
126+
#elif defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
127+
return VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::XAttr;
128+
#endif
129+
return false;
125130
}
126131

127132
FolderWizard::FolderWizard(const AccountStatePtr &account, QWidget *parent)

src/gui/guiutility.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void Utility::markDirectoryAsSyncRoot(const QString &path, const QUuid &accountU
100100
Q_ASSERT(getDirectorySyncRootMarkings(path).first.isEmpty());
101101
Q_ASSERT(getDirectorySyncRootMarkings(path).second.isNull());
102102

103-
auto result1 = FileSystem::Tags::set(path, dirTag(), Theme::instance()->orgDomainName().toUtf8());
103+
auto result1 = FileSystem::Tags::set(path, dirTag(), Theme::instance()->orgDomainName());
104104
if (!result1) {
105105
qCWarning(lcGuiUtility) << QStringLiteral("Failed to set tag on »%1«: %2").arg(path, result1.error())
106106
#ifdef Q_OS_WIN
@@ -110,7 +110,7 @@ void Utility::markDirectoryAsSyncRoot(const QString &path, const QUuid &accountU
110110
return;
111111
}
112112

113-
auto result2 = FileSystem::Tags::set(path, uuidTag(), accountUuid.toString().toUtf8());
113+
auto result2 = FileSystem::Tags::set(path, uuidTag(), accountUuid.toString());
114114
if (!result2) {
115115
qCWarning(lcGuiUtility) << QStringLiteral("Failed to set tag on »%1«: %2").arg(path, result2.error())
116116
#ifdef Q_OS_WIN
@@ -127,7 +127,7 @@ std::pair<QString, QUuid> Utility::getDirectorySyncRootMarkings(const QString &p
127127
auto existingUuidTag = FileSystem::Tags::get(path, uuidTag());
128128

129129
if (existingDirTag.has_value() && existingUuidTag.has_value()) {
130-
return {QString::fromUtf8(existingDirTag.value()), QUuid::fromString(QString::fromUtf8(existingUuidTag.value()))};
130+
return {existingDirTag.value(), QUuid::fromString(existingUuidTag.value())};
131131
}
132132

133133
return {};

src/libsync/CMakeLists.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ set_package_properties(LibreGraphAPI PROPERTIES
77

88
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
99

10-
set(libsync_SRCS
10+
11+
add_library(libsync SHARED
1112
account.cpp
1213
bandwidthmanager.cpp
1314
capabilities.cpp
@@ -45,8 +46,9 @@ set(libsync_SRCS
4546
syncoptions.cpp
4647
theme.cpp
4748

48-
creds/credentialmanager.cpp
4949
creds/abstractcredentials.cpp
50+
creds/credentialmanager.cpp
51+
creds/httpcredentials.cpp
5052
creds/oauth.cpp
5153
creds/jwt.cpp
5254
creds/webfinger.cpp
@@ -65,17 +67,16 @@ set(libsync_SRCS
6567
)
6668

6769
if(WIN32)
68-
list(APPEND libsync_SRCS platform_win.cpp)
70+
target_sources(libsync PRIVATE platform_win.cpp)
6971
elseif(UNIX)
72+
target_sources(libsync PRIVATE xattr.cpp)
7073
if (APPLE)
71-
list(APPEND libsync_SRCS platform_mac.mm)
74+
target_sources(libsync PRIVATE platform_mac.mm)
7275
else()
73-
list(APPEND libsync_SRCS platform_unix.cpp)
76+
target_sources(libsync PRIVATE platform_unix.cpp)
7477
endif()
7578
endif()
7679

77-
set(libsync_SRCS ${libsync_SRCS} creds/httpcredentials.cpp)
78-
7980
# These headers are installed for libopencloudsync to be used by 3rd party apps
8081
INSTALL(
8182
FILES
@@ -85,7 +86,6 @@ INSTALL(
8586
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/${APPLICATION_SHORTNAME}/libsync
8687
)
8788

88-
add_library(libsync SHARED ${libsync_SRCS})
8989
set_target_properties(libsync PROPERTIES EXPORT_NAME SyncCore)
9090

9191
target_link_libraries(libsync

src/libsync/filesystem.cpp

Lines changed: 16 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "common/asserts.h"
1818
#include "common/utility.h"
1919
#include "libsync/discoveryinfo.h"
20+
#include "libsync/xattr.h"
2021

2122
#include <QCoreApplication>
2223
#include <QDirIterator>
@@ -28,10 +29,6 @@
2829

2930
#include <sys/stat.h>
3031

31-
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
32-
#include <sys/xattr.h>
33-
#endif
34-
3532
#ifdef Q_OS_WIN32
3633
#include "common/utility_win.h"
3734
#include <winsock2.h>
@@ -250,52 +247,25 @@ std::optional<uint64_t> FileSystem::getInode(const std::filesystem::path &filena
250247
return info.inode();
251248
}
252249

253-
namespace {
254-
255-
#ifdef Q_OS_LINUX
256-
Q_ALWAYS_INLINE ssize_t getxattr(const char *path, const char *name, void *value, size_t size, u_int32_t, int)
257-
{
258-
return ::getxattr(path, name, value, size);
259-
}
260-
261-
Q_ALWAYS_INLINE int setxattr(const char *path, const char *name, const void *value, size_t size, u_int32_t, int)
262-
{
263-
return ::setxattr(path, name, value, size, 0);
264-
}
265-
266-
Q_ALWAYS_INLINE int removexattr(const char *path, const char *name, int)
267-
{
268-
return ::removexattr(path, name);
269-
}
270-
#endif // Q_OS_LINUX
271-
272-
} // anonymous namespace
273-
274-
std::optional<QByteArray> FileSystem::Tags::get(const QString &path, const QString &key)
250+
std::optional<QString> FileSystem::Tags::get(const QString &path, const QString &key)
275251
{
276252
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
277253
QString platformKey = key;
278254
if (Utility::isLinux()) {
279255
platformKey = QStringLiteral("user.") + platformKey;
280256
}
281-
282-
QByteArray value(MaxValueSize + 1, '\0'); // Add a NUL character to terminate a string
283-
auto size = getxattr(path.toUtf8().constData(), platformKey.toUtf8().constData(), value.data(), MaxValueSize, 0, 0);
284-
if (size != -1) {
285-
value.truncate(size);
286-
return value;
287-
}
257+
return Xattr::getxattr(toFilesystemPath(path), platformKey);
288258
#elif defined(Q_OS_WIN)
289259
QFile file(QStringLiteral("%1:%2").arg(path, key));
290260
if (file.open(QIODevice::ReadOnly)) {
291-
return file.readAll();
261+
return QString::fromUtf8(file.readAll());
292262
}
293263
#endif // Q_OS_MAC || Q_OS_LINUX
294264

295265
return {};
296266
}
297267

298-
OCC::Result<void, QString> FileSystem::Tags::set(const QString &path, const QString &key, const QByteArray &value)
268+
OCC::Result<void, QString> FileSystem::Tags::set(const QString &path, const QString &key, const QString &value)
299269
{
300270
OC_ASSERT(value.size() < MaxValueSize)
301271

@@ -304,62 +274,44 @@ OCC::Result<void, QString> FileSystem::Tags::set(const QString &path, const QStr
304274
if (Utility::isLinux()) {
305275
platformKey = QStringLiteral("user.") + platformKey;
306276
}
307-
308-
auto result = setxattr(path.toUtf8().constData(), platformKey.toUtf8().constData(), value.constData(), value.size(), 0, 0);
309-
if (result != 0) {
310-
return QString::fromUtf8(strerror(errno));
311-
}
312-
313-
return {};
277+
return Xattr::setxattr(toFilesystemPath(path), platformKey, value);
314278
#elif defined(Q_OS_WIN)
315279
QFile file(QStringLiteral("%1:%2").arg(path, key));
316280
if (!file.open(QIODevice::WriteOnly)) {
317281
return file.errorString();
318282
}
319-
auto bytesWritten = file.write(value);
320-
if (bytesWritten != value.size()) {
321-
return QStringLiteral("wrote %1 out of %2 bytes").arg(QString::number(bytesWritten), QString::number(value.size()));
283+
const auto data = value.toUtf8();
284+
auto bytesWritten = file.write(data);
285+
if (bytesWritten != data.size()) {
286+
return QStringLiteral("wrote %1 out of %2 bytes").arg(QString::number(bytesWritten), QString::number(data.size()));
322287
}
323288

324289
return {};
325290
#else
326-
return QStringLiteral("function not implemented");
291+
return u"Not implemented"_s;
327292
#endif // Q_OS_MAC || Q_OS_LINUX
328293
}
329294

330-
bool FileSystem::Tags::remove(const QString &path, const QString &key)
295+
OCC::Result<void, QString> FileSystem::Tags::remove(const QString &path, const QString &key)
331296
{
332297
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
333298
QString platformKey = key;
334299
if (Utility::isLinux()) {
335300
platformKey = QStringLiteral("user.%1").arg(platformKey);
336301
}
337302

338-
auto result = removexattr(path.toUtf8().constData(), platformKey.toUtf8().constData(), 0);
339-
if (result == 0) {
340-
return true;
341-
}
342-
#ifdef Q_OS_MAC
343-
if (errno == ENOATTR) {
344-
#else
345-
if (errno == ENODATA) {
346-
#endif
347-
qCWarning(lcFileSystem) << u"Failed to remove tag" << key << u"from" << path << u"tag doesn't exist";
348-
return true;
349-
}
350-
qCWarning(lcFileSystem) << u"Failed to remove tag" << key << u"from" << path << u":" << strerror(errno);
351-
return false;
303+
return Xattr::removexattr(toFilesystemPath(path), platformKey);
352304
#elif defined(Q_OS_WIN)
353305
const auto fsPath = toFilesystemPath(u"%1:%2"_s.arg(path, key));
354306
std::error_code fileError;
355307
std::filesystem::remove(fsPath, fileError);
356308
if (fileError) {
357309
qCWarning(lcFileSystem) << u"Failed to remove tag" << key << u"from" << path << u":" << fsPath << u"error:" << fileError.message();
358-
return false;
310+
return QString::fromStdString(fileError.message());
359311
}
360-
return true;
312+
return {};
361313
#else
362-
return false;
314+
return u"Not implemented"_s;
363315
#endif // Q_OS_MAC || Q_OS_LINUX
364316
}
365317
} // namespace OCC

src/libsync/filesystem.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ namespace FileSystem {
128128
bool OPENCLOUD_SYNC_EXPORT removeRecursively(const QString &path, RemoveEntryList *success, RemoveEntryList *locked, RemoveErrorList *errors);
129129

130130
namespace Tags {
131-
std::optional<QByteArray> OPENCLOUD_SYNC_EXPORT get(const QString &path, const QString &key);
132-
OCC::Result<void, QString> OPENCLOUD_SYNC_EXPORT set(const QString &path, const QString &key, const QByteArray &value);
133-
bool OPENCLOUD_SYNC_EXPORT remove(const QString &path, const QString &key);
131+
std::optional<QString> OPENCLOUD_SYNC_EXPORT get(const QString &path, const QString &key);
132+
OCC::Result<void, QString> OPENCLOUD_SYNC_EXPORT set(const QString &path, const QString &key, const QString &value);
133+
OCC::Result<void, QString> OPENCLOUD_SYNC_EXPORT remove(const QString &path, const QString &key);
134134
}
135135
}
136136

src/libsync/xattr.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// SPDX-FileCopyrightText: 2025 Hannah von Reth <h.vonreth@opencloud.eu>
3+
4+
#include "xattr.h"
5+
6+
#include <sys/xattr.h>
7+
8+
#include "common/filesystembase.h"
9+
10+
namespace OCC {
11+
namespace FileSystem {
12+
std::optional<QString> Xattr::getxattr(const std::filesystem::path &path, const QString &name)
13+
{
14+
QByteArray value;
15+
ssize_t res = 0;
16+
do {
17+
value.resize(value.size() + 255);
18+
#ifdef Q_OS_MAC
19+
res = ::getxattr(path.c_str(), name.toUtf8().constData(), value.data(), value.size(), 0, XATTR_NOFOLLOW);
20+
#else
21+
res = ::lgetxattr(path.c_str(), name.toUtf8().constData(), value.data(), value.size());
22+
#endif
23+
} while (res == -1 && errno == ERANGE);
24+
if (res > 0) {
25+
value.resize(res);
26+
return QString::fromUtf8(value);
27+
} else {
28+
return {};
29+
}
30+
}
31+
32+
Result<void, QString> Xattr::setxattr(const std::filesystem::path &path, const QString &name, const QString &value)
33+
{
34+
const auto data = value.toUtf8();
35+
#ifdef Q_OS_MAC
36+
const auto result = ::setxattr(path.c_str(), name.toUtf8().constData(), data.constData(), data.size(), 0, XATTR_NOFOLLOW);
37+
#else
38+
const auto result = ::lsetxattr(path.c_str(), name.toUtf8().constData(), data.constData(), data.size(), 0);
39+
#endif
40+
if (result != 0) {
41+
return QString::fromUtf8(strerror(errno));
42+
}
43+
return {};
44+
}
45+
46+
Result<void, QString> Xattr::removexattr(const std::filesystem::path &path, const QString &name)
47+
{
48+
#ifdef Q_OS_MAC
49+
const auto result = ::removexattr(path.c_str(), name.toUtf8().constData(), 0);
50+
#else
51+
const auto result = ::lremovexattr(path.c_str(), name.toUtf8().constData());
52+
#endif
53+
54+
#ifdef Q_OS_MAC
55+
if (errno == ENOATTR) {
56+
#else
57+
if (errno == ENODATA) {
58+
#endif
59+
qCWarning(lcFileSystem) << u"Failed to remove tag" << name << u"from" << path.native() << u"tag doesn't exist";
60+
return {};
61+
}
62+
if (result != 0) {
63+
return QString::fromUtf8(strerror(errno));
64+
}
65+
return {};
66+
}
67+
}
68+
}

src/libsync/xattr.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// SPDX-FileCopyrightText: 2025 Hannah von Reth <h.vonreth@opencloud.eu>
3+
4+
#pragma once
5+
6+
#include "libsync/common/result.h"
7+
#include "libsync/opencloudsynclib.h"
8+
9+
#include <filesystem>
10+
#include <optional>
11+
12+
#include <QString>
13+
14+
namespace OCC {
15+
namespace FileSystem {
16+
namespace Xattr {
17+
OPENCLOUD_SYNC_EXPORT std::optional<QString> getxattr(const std::filesystem::path &path, const QString &name);
18+
OPENCLOUD_SYNC_EXPORT Result<void, QString> setxattr(const std::filesystem::path &path, const QString &name, const QString &value);
19+
20+
OPENCLOUD_SYNC_EXPORT Result<void, QString> removexattr(const std::filesystem::path &path, const QString &name);
21+
}
22+
}
23+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
if (NOT WIN32)
12
add_vfs_plugin(NAME xattr
23
SRC
34
vfs_xattr.cpp
45
)
6+
endif()

0 commit comments

Comments
 (0)