fix: check file permission reliability with a test

rather than trying to figure out the filesystem type.

Signed-off-by: Tamás Bari <adaorcpp@gmail.com>
Signed-off-by: Jyrki Gadinger <nilsding@nilsding.org>
This commit is contained in:
Tamás Bari 2025-10-14 10:33:32 +02:00 committed by Jyrki Gadinger
parent fb653ba7c1
commit 4cd37220a6
6 changed files with 68 additions and 21 deletions

View File

@ -145,6 +145,9 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const QString &path, bool exclu
if (bname.startsWith(QLatin1String(".nextcloudsync.log"), Qt::CaseInsensitive)) { // ".nextcloudsync.log*"
return CSYNC_FILE_SILENTLY_EXCLUDED;
}
if (bname.startsWith(QLatin1String(".nextcloudpermissions.log"), Qt::CaseInsensitive)) { // ".nextcloudpermissions.log*"
return CSYNC_FILE_SILENTLY_EXCLUDED;
}
}
// check the strlen and ignore the file if its name is longer than 254 chars.

View File

@ -248,7 +248,6 @@ QString Folder::shortGuiLocalPath() const
return QDir::toNativeSeparators(p);
}
bool Folder::ignoreHiddenFiles()
{
bool re(_definition.ignoreHiddenFiles);
@ -397,7 +396,6 @@ void Folder::etagRetrievedFromSyncEngine(const QByteArray &etag, const QDateTime
_lastEtag = etag;
}
void Folder::showSyncResultPopup()
{
if (_syncResult.firstItemNew()) {
@ -643,7 +641,6 @@ void Folder::slotWatchedPathChanged(const QStringView &path, const ChangeReason
}
#endif
SyncJournalFileRecord record;
if (!_journal.getFileRecord(relativePathBytes, &record)) {
qCWarning(lcFolder) << "could not get file from local DB" << relativePathBytes;
@ -1159,6 +1156,7 @@ void Folder::startSync(const QStringList &pathList)
}
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
_engine->setFilesystemPermissionsReliable(_folderWatcher->canSetPermissions());
correctPlaceholderFiles();
@ -1310,7 +1308,6 @@ void Folder::slotSyncFinished(bool success)
}
}
emit syncStateChange();
// The syncFinished result that is to be triggered here makes the folderman
@ -1696,6 +1693,7 @@ void Folder::registerFolderWatcher()
connect(_folderWatcher.data(), &FolderWatcher::filesLockImposed, this, &Folder::slotFilesLockImposed, Qt::UniqueConnection);
_folderWatcher->init(path());
_folderWatcher->startNotificatonTest(path() + QLatin1String(".nextcloudsync.log"));
_folderWatcher->performSetPermissionsTest(path() + QLatin1String(".nextcloudpermissions.log"));
connect(_engine.data(), &SyncEngine::lockFileDetected, _folderWatcher.data(), &FolderWatcher::slotLockFileDetectedExternally);
}
@ -1918,5 +1916,4 @@ QString FolderDefinition::defaultJournalPath(AccountPtr account)
return SyncJournalDb::makeDbName(localPath, account->url(), targetPath, account->credentials()->user());
}
} // namespace OCC

View File

@ -70,7 +70,13 @@ bool FolderWatcher::isReliable() const
return _isReliable;
}
void FolderWatcher::appendSubPaths(QDir dir, QStringList& subPaths) {
bool FolderWatcher::canSetPermissions() const
{
return _canSetPermissions;
}
void FolderWatcher::appendSubPaths(QDir dir, QStringList &subPaths)
{
QStringList newSubPaths = dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
for (int i = 0; i < newSubPaths.size(); i++) {
QString path = dir.path() + "/" + newSubPaths[i];
@ -101,6 +107,40 @@ void FolderWatcher::startNotificatonTest(const QString &path)
startNotificationTestWhenReady();
}
void FolderWatcher::performSetPermissionsTest(const QString &path)
{
_canSetPermissions = true;
if (!QFile::exists(path)) {
QFile f(path);
f.open(QIODevice::WriteOnly);
if (!f.isOpen()) {
qCWarning(lcFolderWatcher()) << "Failed to create test file: " << path;
return;
}
f.write("test");
f.close();
}
if (!FileSystem::isWritable(path)) {
FileSystem::setFileReadOnly(path, false);
if (!FileSystem::isWritable(path)) {
qCWarning(lcFolderWatcher()) << "Cannot make file readable: " << path;
_canSetPermissions = false;
QFile(path).remove();
return;
}
}
FileSystem::setFileReadOnly(path, true);
if (FileSystem::isWritable(path)) {
qCWarning(lcFolderWatcher()) << "Cannot make file read-only: " << path;
_canSetPermissions = false;
}
QFile(path).remove();
}
void FolderWatcher::startNotificationTestWhenReady()
{
if (!_d->_ready) {

View File

@ -61,6 +61,8 @@ public:
*/
[[nodiscard]] bool isReliable() const;
[[nodiscard]] bool canSetPermissions() const;
/**
* Triggers a change in the path and verifies a notification arrives.
*
@ -69,6 +71,13 @@ public:
*/
void startNotificatonTest(const QString &path);
/**
* Attempts to set a file's permissions to read-only.
*
* If that fails, the folderwatcher marsk itself as not able to set permissions reliably.
*/
void performSetPermissionsTest(const QString &path);
/// For testing linux behavior only
[[nodiscard]] int testLinuxWatchCount() const;
@ -83,8 +92,8 @@ signals:
void pathChanged(const QString &path);
/*
* Emitted when lock files were removed
*/
* Emitted when lock files were removed
*/
void filesLockReleased(const QSet<QString> &files);
/*
@ -129,6 +138,7 @@ private:
QSet<QString> _lastPaths;
Folder *_folder;
bool _isReliable = true;
bool _canSetPermissions = true;
bool _shouldWatchForFileUnlocking = false;

View File

@ -633,19 +633,7 @@ void SyncEngine::startSync()
_remnantReadOnlyFolders.clear();
_discoveryPhase = std::make_unique<DiscoveryPhase>();
#if defined Q_OS_LINUX
const auto fileSystemInfo = QStorageInfo{_localPath};
qCInfo(lcEngine()) << "File system type for current sync folder:" << fileSystemInfo.fileSystemType();
if (fileSystemInfo.fileSystemType() == "NTFS") {
_discoveryPhase->_fileSystemReliablePermissions = false;
} else {
_discoveryPhase->_fileSystemReliablePermissions = true;
}
#else
_discoveryPhase->_fileSystemReliablePermissions = true;
#endif
_discoveryPhase->_fileSystemReliablePermissions = _filesystemPermissionsReliable;
_discoveryPhase->_leadingAndTrailingSpacesFilesAllowed = _leadingAndTrailingSpacesFilesAllowed;
_discoveryPhase->_account = _account;
_discoveryPhase->_excludes = _excludedFiles.data();
@ -1307,6 +1295,11 @@ const SyncEngine::SingleItemDiscoveryOptions &SyncEngine::singleItemDiscoveryOpt
return _singleItemDiscoveryOptions;
}
void SyncEngine::setFilesystemPermissionsReliable(bool reliable)
{
_filesystemPermissionsReliable = reliable;
}
bool SyncEngine::shouldDiscoverLocally(const QString &path) const
{
auto result = false;

View File

@ -125,6 +125,8 @@ public:
[[nodiscard]] QSharedPointer<OwncloudPropagator> getPropagator() const { return _propagator; } // for the test
[[nodiscard]] const SyncEngine::SingleItemDiscoveryOptions &singleItemDiscoveryOptions() const;
void setFilesystemPermissionsReliable(bool reliable);
public slots:
void setSingleItemDiscoveryOptions(const OCC::SyncEngine::SingleItemDiscoveryOptions &singleItemDiscoveryOptions);
@ -412,6 +414,8 @@ private:
SingleItemDiscoveryOptions _singleItemDiscoveryOptions;
QList<SyncFileItemPtr> _remnantReadOnlyFolders;
bool _filesystemPermissionsReliable = true;
};
}