Skip to content

Commit

Permalink
Merge pull request #5958 from nextcloud/backport/5872/stable-3.9
Browse files Browse the repository at this point in the history
[stable-3.9] Do not modify discovered files on disk if not necessary
  • Loading branch information
claucambra authored Aug 8, 2023
2 parents dfd5fa5 + 832f0f8 commit f22db46
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 8 deletions.
6 changes: 3 additions & 3 deletions src/common/filesystembase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,17 @@ void FileSystem::setFolderMinimumPermissions(const QString &filename)
#endif
}


void FileSystem::setFileReadOnlyWeak(const QString &filename, bool readonly)
bool FileSystem::setFileReadOnlyWeak(const QString &filename, bool readonly)
{
QFile file(filename);
QFile::Permissions permissions = file.permissions();

if (!readonly && (permissions & QFile::WriteOwner)) {
return; // already writable enough
return false; // already writable enough
}

setFileReadOnly(filename, readonly);
return true;
}

bool FileSystem::rename(const QString &originFileName,
Expand Down
2 changes: 1 addition & 1 deletion src/common/filesystembase.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ namespace FileSystem {
* This means that it will preserve explicitly set rw-r--r-- permissions even
* when the umask is 0002. (setFileReadOnly() would adjust to rw-rw-r--)
*/
void OCSYNC_EXPORT setFileReadOnlyWeak(const QString &filename, bool readonly);
bool OCSYNC_EXPORT setFileReadOnlyWeak(const QString &filename, bool readonly);

/**
* @brief Try to set permissions so that other users on the local machine can not
Expand Down
13 changes: 9 additions & 4 deletions src/libsync/syncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
// mini-jobs later on, we just update metadata right now.

if (item->_direction == SyncFileItem::Down) {
auto modificationHappened = false; // Decides whether or not we modify file metadata
QString filePath = _localPath + item->_file;

// If the 'W' remote permission changed, update the local filesystem
Expand All @@ -365,15 +366,18 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
&& prev.isValid()
&& prev._remotePerm.hasPermission(RemotePermissions::CanWrite) != item->_remotePerm.hasPermission(RemotePermissions::CanWrite)) {
const bool isReadOnly = !item->_remotePerm.isNull() && !item->_remotePerm.hasPermission(RemotePermissions::CanWrite);
FileSystem::setFileReadOnlyWeak(filePath, isReadOnly);
modificationHappened = FileSystem::setFileReadOnlyWeak(filePath, isReadOnly);
}

modificationHappened |= item->_size != prev._fileSize;

auto rec = item->toSyncJournalFileRecordWithInode(filePath);
if (rec._checksumHeader.isEmpty())
rec._checksumHeader = prev._checksumHeader;
rec._serverHasIgnoredFiles |= prev._serverHasIgnoredFiles;

// Ensure it's a placeholder file on disk
if (item->_type == ItemTypeFile) {
if (item->_type == ItemTypeFile && _syncOptions._vfs->mode() != Vfs::Off) {
const auto result = _syncOptions._vfs->convertToPlaceholder(filePath, *item);
if (!result) {
item->_status = SyncFileItem::Status::NormalError;
Expand All @@ -382,10 +386,11 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
emit itemCompleted(item, ErrorCategory::GenericError);
return;
}
modificationHappened = true;
}

// Update on-disk virtual file metadata
if (item->_type == ItemTypeVirtualFile) {
if (modificationHappened && item->_type == ItemTypeVirtualFile) {
auto r = _syncOptions._vfs->updateMetadata(filePath, item->_modtime, item->_size, item->_fileId);
if (!r) {
item->_status = SyncFileItem::Status::NormalError;
Expand All @@ -394,7 +399,7 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
emit itemCompleted(item, ErrorCategory::GenericError);
return;
}
} else {
} else if (modificationHappened || prev._modtime != item->_modtime) {
if (!FileSystem::setModTime(filePath, item->_modtime)) {
item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Could not update file metadata: %1").arg(filePath);
Expand Down
6 changes: 6 additions & 0 deletions test/syncenginetestutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ void DiskFileModifier::setE2EE([[maybe_unused]] const QString &relativePath, [[m
{
}

QFile DiskFileModifier::find(const QString &relativePath) const
{
const auto path = _rootDir.filePath(relativePath);
return QFile(path);
}

FileInfo FileInfo::A12_B12_C12_S12()
{
FileInfo fi { QString {}, {
Expand Down
2 changes: 2 additions & 0 deletions test/syncenginetestutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ class DiskFileModifier : public FileModifier
void setModTime(const QString &relativePath, const QDateTime &modTime) override;
void modifyLockState(const QString &relativePath, LockState lockState, int lockType, const QString &lockOwner, const QString &lockOwnerId, const QString &lockEditorId, quint64 lockTime, quint64 lockTimeout) override;
void setE2EE(const QString &relativepath, const bool enabled) override;

[[nodiscard]] QFile find(const QString &relativePath) const;
};

class FileInfo : public FileModifier
Expand Down
24 changes: 24 additions & 0 deletions test/testsyncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "propagatorjobs.h"
#include "caseclashconflictsolver.h"

#include <QFile>
#include <QtTest>

using namespace OCC;
Expand Down Expand Up @@ -920,6 +921,29 @@ private slots:
QCOMPARE(QFileInfo(fakeFolder.localPath() + "foo").lastModified(), datetime);
}

// A local file should not be modified after upload to server if nothing has changed.
void testLocalFileInitialMtime()
{
constexpr auto fooFolder = "foo/";
constexpr auto barFile = "foo/bar";

FakeFolder fakeFolder{FileInfo{}};
fakeFolder.localModifier().mkdir(fooFolder);
fakeFolder.localModifier().insert(barFile);

const auto localDiskFileModifier = dynamic_cast<DiskFileModifier &>(fakeFolder.localModifier());

const auto localFile = localDiskFileModifier.find(barFile);
const auto localFileInfo = QFileInfo(localFile);
const auto expectedMtime = localFileInfo.metadataChangeTime();

QVERIFY(fakeFolder.syncOnce());
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());

const auto currentMtime = localFileInfo.metadataChangeTime();
QCOMPARE(currentMtime, expectedMtime);
}

/**
* Checks whether subsequent large uploads are skipped after a 507 error
*/
Expand Down

0 comments on commit f22db46

Please sign in to comment.