Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
db2f260
Initial implementation for tac support on macOS
Jan 30, 2024
7ba3fcb
Added xattr support in linux
Jan 30, 2024
e4befd7
Fix(l10n): Update translations from Transifex
nextcloud-bot Jan 31, 2024
991c9c5
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 1, 2024
b213514
wait longer to get the contextual menu entries: may be necessary
mgallien Feb 2, 2024
df11c0f
fix(i18n): uppercase ID
rakekniven Feb 4, 2024
886d97b
fix(i18n): Changed spelling of "public key"
rakekniven Feb 4, 2024
dcac579
chore: update workflows from templates
skjnldsv Feb 5, 2024
bde5af9
Build(deps): Bump codecov/codecov-action from 3 to 4
dependabot[bot] Feb 5, 2024
2720921
suppress deprecated warnings from openssl
mgallien Jan 31, 2024
25a7bf1
Run swift-format on swift code
claucambra Jan 22, 2024
88d83e3
Add .swift-format.json
claucambra Jan 23, 2024
096f560
Clean up file provider extension property declarations and init
claucambra Feb 5, 2024
f451958
Cllean up function and method calls in File Provider Extension
claucambra Feb 5, 2024
c115c39
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 7, 2024
a81e818
Modernize networkReplyErrorString by using const auto.
camilasan Feb 1, 2024
b947b8a
Modernize extractErrorMessage and AbstractNetworkJob::errorStringPars…
camilasan Feb 2, 2024
f09cef7
Update 'no connection' error text to a more user friendly message.
camilasan Feb 2, 2024
05a5c2b
Show systray error message when there is a network error.
camilasan Feb 2, 2024
d9cd1a4
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 8, 2024
aecc92c
Do not create systray notification if there are no errors.
camilasan Feb 7, 2024
6087806
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 9, 2024
42c8d74
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 11, 2024
a370f4b
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 12, 2024
f3090e6
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 13, 2024
8ae927a
docs(conffile) Update chunk sizes to match v2 chunking PR
joshtrichards Nov 20, 2023
430bb58
Properly report Undefined sync status when multiple folders syncing
claucambra Apr 4, 2023
d3d1ad7
Use auto and const auto where possible in trayOverallStatus
claucambra Apr 4, 2023
001d773
Use bools rather than unnecessary ints in folderman trayoverallstatus
claucambra Apr 4, 2023
c7998a8
Do an early break of folder state check loop when errors seen
claucambra Apr 4, 2023
c0cc3b2
fix binding loop with palette assignments
mgallien Feb 8, 2024
1ea0fc8
ensure role hideDownload from ShareModel has a boolean default value
mgallien Feb 8, 2024
72c2d03
fix QML warnings about accessing undefined parent property
mgallien Feb 8, 2024
638d32e
fix more issues from qml in share dialog
mgallien Feb 8, 2024
666a751
Fix(l10n): Update translations from Transifex
nextcloud-bot Feb 14, 2024
8abe081
Do not upload modified PDF file while it is open in Kofax PowerPDF on…
allexzander Feb 10, 2024
32021e0
Improved cliend side sync process for tags. Some code clean-up.
Feb 14, 2024
f883c34
Merge branch 'master' into addtagsupportmac
Runtemund Feb 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/common/preparedsqlquerymanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class OCSYNC_EXPORT PreparedSqlQueryManager
GetE2EeLockedFoldersQuery,
DeleteE2EeLockedFolderQuery,
ListAllTopLevelE2eeFoldersStatusLessThanQuery,
UpdateTagListQuery,
GetTagListQuery,

PreparedQueryCount
};
Expand Down
65 changes: 61 additions & 4 deletions src/common/syncjournaldb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Q_LOGGING_CATEGORY(lcDb, "nextcloud.sync.database", QtInfoMsg)
#define GET_FILE_RECORD_QUERY \
"SELECT path, inode, modtime, type, md5, fileid, remotePerm, filesize," \
" ignoredChildrenRemote, contentchecksumtype.name || ':' || contentChecksum, e2eMangledName, isE2eEncrypted, " \
" lock, lockOwnerDisplayName, lockOwnerId, lockType, lockOwnerEditor, lockTime, lockTimeout, isShared, lastShareStateFetchedTimestmap, sharedByMe" \
" lock, lockOwnerDisplayName, lockOwnerId, lockType, lockOwnerEditor, lockTime, lockTimeout, isShared, lastShareStateFetchedTimestmap, sharedByMe, tagList" \
" FROM metadata" \
" LEFT JOIN checksumtype as contentchecksumtype ON metadata.contentChecksumTypeId == contentchecksumtype.id"

Expand Down Expand Up @@ -77,6 +77,7 @@ static void fillFileRecordFromGetQuery(SyncJournalFileRecord &rec, SqlQuery &que
rec._isShared = query.intValue(19) > 0;
rec._lastShareStateFetchedTimestamp = query.int64Value(20);
rec._sharedByMe = query.intValue(21) > 0;
rec._tagList = query.baValue(22);
}

static QByteArray defaultJournalMode(const QString &dbPath)
Expand Down Expand Up @@ -832,6 +833,8 @@ bool SyncJournalDb::updateMetadataTableStructure()
}
commitInternal(QStringLiteral("update database structure: add basePath index"));

addColumn(QStringLiteral("tagList"), QStringLiteral("TEXT"));

return re;
}

Expand Down Expand Up @@ -958,7 +961,8 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
<< "lock editor:" << record._lockstate._lockEditorApp
<< "sharedByMe:" << record._sharedByMe
<< "isShared:" << record._isShared
<< "lastShareStateFetchedTimestamp:" << record._lastShareStateFetchedTimestamp;
<< "lastShareStateFetchedTimestamp:" << record._lastShareStateFetchedTimestamp
<< "tagList:"<<record._tagList;

const qint64 phash = getPHash(record._path);
if (!checkConnect()) {
Expand All @@ -984,8 +988,8 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
const auto query = _queryManager.get(PreparedSqlQueryManager::SetFileRecordQuery, QByteArrayLiteral("INSERT OR REPLACE INTO metadata "
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm, filesize, ignoredChildrenRemote, "
"contentChecksum, contentChecksumTypeId, e2eMangledName, isE2eEncrypted, lock, lockType, lockOwnerDisplayName, lockOwnerId, "
"lockOwnerEditor, lockTime, lockTimeout, isShared, lastShareStateFetchedTimestmap, sharedByMe) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28);"),
"lockOwnerEditor, lockTime, lockTimeout, isShared, lastShareStateFetchedTimestmap, sharedByMe, tagList) "
"VALUES (?1 , ?2, ?3 , ?4 , ?5 , ?6 , ?7, ?8 , ?9 , ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29);"),
_db);
if (!query) {
return query->error();
Expand Down Expand Up @@ -1019,6 +1023,7 @@ Result<void, QString> SyncJournalDb::setFileRecord(const SyncJournalFileRecord &
query->bindValue(26, record._isShared);
query->bindValue(27, record._lastShareStateFetchedTimestamp);
query->bindValue(28, record._sharedByMe);
query->bindValue(29, record._tagList);

if (!query->exec()) {
return query->error();
Expand Down Expand Up @@ -1497,6 +1502,58 @@ int SyncJournalDb::getFileRecordCount()
return -1;
}

bool SyncJournalDb::updateMetadataTagList(const QString &filename,const QByteArray* tagList)
{
QMutexLocker locker(&_mutex);

qCInfo(lcDb) << "Updating file tag list " << filename;

if (!checkConnect()) {
qCWarning(lcDb) << "Failed to connect database.";
return false;
}

const qint64 phash = getPHash(filename.toUtf8());

const auto query = _queryManager.get(PreparedSqlQueryManager::UpdateTagListQuery,
QByteArrayLiteral("UPDATE metadata"
" SET tagList = ?2"
" WHERE phash = ?1;"),
_db);
if (!query) {
return false;
}
query->bindValue(1, phash);
query->bindValue(2, *tagList);
return query->exec();
}

QByteArray SyncJournalDb::tagList(const QString &file)
{
QMutexLocker locker(&_mutex);
if (!checkConnect())
return QByteArray();

const qint64 phash = getPHash(file.toUtf8());

const auto query = _queryManager.get(PreparedSqlQueryManager::GetTagListQuery,
QByteArrayLiteral("SELECT tagList FROM metadata"
" WHERE phash = ?1;"),
_db);
if (!query) {
return QByteArray();
}

query->bindValue(1, phash);
if (!query->exec())return QByteArray();

auto next = query->next();
if (!next.ok || !next.hasData)return QByteArray();

QByteArray result = query->baValue(0);
return result;
}

bool SyncJournalDb::updateFileRecordChecksum(const QString &filename,
const QByteArray &contentChecksum,
const QByteArray &contentChecksumType)
Expand Down
10 changes: 10 additions & 0 deletions src/common/syncjournaldb.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,16 @@ class OCSYNC_EXPORT SyncJournalDb : public QObject
void setDataFingerprint(const QByteArray &dataFingerprint);
QByteArray dataFingerprint();

/*!
* \brief Update the taglist in the metadata table.
*/
bool updateMetadataTagList(const QString &file,
const QByteArray* tagList);

/*!
* \brief Returns the taglist of the queried file.
*/
QByteArray tagList(const QString &file);

// Conflict record functions

Expand Down
3 changes: 2 additions & 1 deletion src/common/syncjournalfilerecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ bool operator==(const SyncJournalFileRecord &lhs,
&& lhs._fileSize == rhs._fileSize
&& lhs._remotePerm == rhs._remotePerm
&& lhs._serverHasIgnoredFiles == rhs._serverHasIgnoredFiles
&& lhs._checksumHeader == rhs._checksumHeader;
&& lhs._checksumHeader == rhs._checksumHeader
&& lhs._tagList == rhs._tagList;
}
}
1 change: 1 addition & 0 deletions src/common/syncjournalfilerecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class OCSYNC_EXPORT SyncJournalFileRecord
bool _isShared = false;
qint64 _lastShareStateFetchedTimestamp = 0;
bool _sharedByMe = false;
QByteArray _tagList;
};

QDebug& operator<<(QDebug &stream, const SyncJournalFileRecord::EncryptionStatus status);
Expand Down
2 changes: 2 additions & 0 deletions src/csync/csync.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ struct OCSYNC_EXPORT csync_file_stat_s {
QByteArray directDownloadCookies;
QByteArray original_path; // only set if locale conversion fails

QByteArray tagList; // \n-separated List of tags

// In the local tree, this can hold a checksum and its type if it is
// computed during discovery for some reason.
// In the remote tree, this will have the server checksum, if available.
Expand Down
68 changes: 68 additions & 0 deletions src/csync/vio/csync_vio_local_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@

#include <memory>

#ifdef __APPLE__
#include <CoreFoundation/CFBundle.h>
#include <CoreServices/CoreServices.h>
#endif

#ifdef __linux__
#include <sys/xattr.h>
#endif

#include "c_private.h"
#include "c_lib.h"
#include "csync.h"
Expand Down Expand Up @@ -120,6 +129,65 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *h
file_stat->type = ItemTypeSkip;
}


#ifdef __APPLE__

// Create necessary system related objects
CFStringRef cfstr = CFStringCreateWithCString(kCFAllocatorDefault,
fullPath.constData(),
kCFStringEncodingUTF8);
CFURLRef urlref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
cfstr,
kCFURLPOSIXPathStyle,
dirent->d_type == DT_DIR);

// Query tags
CFArrayRef labels=NULL;
Boolean result = CFURLCopyResourcePropertyForKey(urlref,
kCFURLTagNamesKey,
&labels,
NULL);

if(result==true && labels != NULL){
// Extract the labels to our array
int count = (int) CFArrayGetCount(labels);

if(count>0){
QStringList tagarray;

for(int index=0;index<count;index++){
CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(labels,index);
if(CFStringGetLength(str)>0)tagarray << QString::fromCFString(str);
}
tagarray.sort(Qt::CaseInsensitive);
QString tagList = tagarray.join(QChar(0x000A));
file_stat->tagList=tagList.toUtf8();
}
}

// Clean up
CFRelease(cfstr);
CFRelease(urlref);
if(labels!=NULL)CFRelease(labels);

#endif

#ifdef __linux__
const int sz=4096;
char buffer[sz];
int result = getxattr(fullPath.constData(),"user.xdg.tags",buffer,sz);

if(result>0)
{
// Data is store usually as comma(,) separated list.
// So we just need to replace ',' by '\n'.
QByteArray tagList = QByteArray(buffer,result);
tagList.replace(',','\n');
printf("%s\n",buffer);
file_stat->tagList= tagList;
}
#endif

Comment on lines +132 to +190
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: the formatting of the code here does not match the rest of the code, please use 4-space indentation and leave spaces in between operators, as well as if statements and their parenthesis :)

// Override type for virtual files if desired
if (vfs) {
// Directly modifies file_stat->type.
Expand Down
4 changes: 3 additions & 1 deletion src/gui/editlocallyjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,9 @@ void EditLocallyJob::fetchRemoteFileParentInfo()
QByteArrayLiteral("http://owncloud.org/ns:size"),
QByteArrayLiteral("http://owncloud.org/ns:id"),
QByteArrayLiteral("http://owncloud.org/ns:permissions"),
QByteArrayLiteral("http://owncloud.org/ns:checksums")};
QByteArrayLiteral("http://owncloud.org/ns:checksums"),
QByteArrayLiteral("http://owncloud.org/ns:tags"),
QByteArrayLiteral("http://nextcloud.org/ns:system-tags")};

job->setProperties(props);
connect(job, &LsColJob::directoryListingIterated, this, &EditLocallyJob::slotDirectoryListingIterated);
Expand Down
4 changes: 1 addition & 3 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,6 @@ void Folder::slotWatchedPathChanged(const QString &path, ChangeReason reason)
qCDebug(lcFolder) << "Changed path is not contained in folder, ignoring:" << path;
return;
}

auto relativePath = path.midRef(this->path().size());

if (pathIsIgnored(path)) {
Expand Down Expand Up @@ -610,7 +609,7 @@ void Folder::slotWatchedPathChanged(const QString &path, ChangeReason reason)
// an attribute change (pin state) that caused the notification
bool spurious = false;
if (record.isValid()
&& !FileSystem::fileChanged(path, record._fileSize, record._modtime)) {
&& !FileSystem::fileChanged(path, record._fileSize, record._modtime,record._tagList)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&& !FileSystem::fileChanged(path, record._fileSize, record._modtime,record._tagList)) {
&& !FileSystem::fileChanged(path, record._fileSize, record._modtime, record._tagList)) {

spurious = true;

if (auto pinState = _vfs->pinState(relativePath.toString())) {
Expand All @@ -628,7 +627,6 @@ void Folder::slotWatchedPathChanged(const QString &path, ChangeReason reason)
}
}
warnOnNewExcludedItem(record, relativePath);

emit watchedFileChangedExternally(path);

// Also schedule this folder for a sync, but only after some delay:
Expand Down
7 changes: 4 additions & 3 deletions src/gui/folderwatcher_mac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ static void callback(
| kFSEventStreamEventFlagItemInodeMetaMod // for mtime change
| kFSEventStreamEventFlagItemRenamed // also coming for moves to trash in finder
| kFSEventStreamEventFlagItemModified // for content change
| kFSEventStreamEventFlagItemCloned; // for cloned items (since 10.13)
//We ignore other flags, e.g. for owner change, xattr change, Finder label change etc
| kFSEventStreamEventFlagItemCloned // for cloned items (since 10.13)
| kFSEventStreamEventFlagItemXattrMod; // for tags change (which are stored as xattr)
//We ignore other flags, e.g. for owner change etc.

QStringList paths;
CFArrayRef eventPaths = (CFArrayRef)eventPathsVoid;
Expand Down Expand Up @@ -111,7 +112,7 @@ void FolderWatcherPrivate::startWatching()
pathsToWatch,
kFSEventStreamEventIdSinceNow,
0, // latency
kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagIgnoreSelf);
kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagIgnoreSelf | kFSEventStreamEventFlagItemXattrMod);

CFRelease(pathsToWatch);
CFRelease(folderCF);
Expand Down
2 changes: 2 additions & 0 deletions src/libsync/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ set(libsync_SRCS
encryptedfoldermetadatahandler.cpp
filesystem.h
filesystem.cpp
filetags.h
filetags.cpp
helpers.cpp
httplogger.h
httplogger.cpp
Expand Down
18 changes: 17 additions & 1 deletion src/libsync/discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "common/filesystembase.h"
#include "common/syncjournaldb.h"
#include "filesystem.h"
#include "filetags.h"
#include "syncfileitem.h"
#include "progressdispatcher.h"
#include <QDebug>
Expand Down Expand Up @@ -482,7 +483,8 @@ void ProcessDirectoryJob::processFile(PathTuple path,
<< " | e2ee: " << dbEntry.isE2eEncrypted() << "/" << serverEntry.isE2eEncrypted()
<< " | e2eeMangledName: " << dbEntry.e2eMangledName() << "/" << serverEntry.e2eMangledName
<< " | file lock: " << localFileIsLocked << "//" << serverFileIsLocked
<< " | metadata missing: /" << localEntry.isMetadataMissing << '/';
<< " | metadata missing: /" << localEntry.isMetadataMissing << '/'
<< " | tagList: " << dbEntry._tagList << "//" << localEntry.tagList << "//" << serverEntry.tagList;

if (localEntry.isValid()
&& !serverEntry.isValid()
Expand All @@ -491,6 +493,19 @@ void ProcessDirectoryJob::processFile(PathTuple path,
qCWarning(lcDisco) << "File" << path._original << "was modified before the last sync run and is not in the sync journal and server";
}

if(localEntry.isValid()
&& dbEntry.isValid()) {
Comment on lines +496 to +497
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(localEntry.isValid()
&& dbEntry.isValid()) {
if(localEntry.isValid() && dbEntry.isValid()) {


// Tag synchronization
FileTagManager::syncTags(_discoveryData->_account,
_discoveryData->_statedb,
_discoveryData->_localDir,
path._original,
localEntry,
serverEntry,
dbEntry);
}

if (_discoveryData->isRenamed(path._original)) {
qCDebug(lcDisco) << "Ignoring renamed";
return; // Ignore this.
Expand Down Expand Up @@ -656,6 +671,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
item->_lockEditorApp = serverEntry.lockEditorApp;
item->_lockTime = serverEntry.lockTime;
item->_lockTimeout = serverEntry.lockTimeout;
item->_tagList = serverEntry.tagList;

qCDebug(lcDisco()) << "item lock for:" << item->_file
<< item->_locked
Expand Down
Loading