Skip to content

Commit

Permalink
try to enforce the windows compatibility as guessed from server
Browse files Browse the repository at this point in the history
for now simple rule to guess if the server has windows naming enforced

if windows naming is enforced, we enforce it for new files

if not, we do not care

for now limited to spaces removal

more to come

Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
  • Loading branch information
mgallien committed Feb 17, 2025
1 parent 92fe147 commit e8baa62
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/libsync/discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const Entries &ent
const auto hasLeadingOrTrailingSpaces = excluded == CSYNC_FILE_EXCLUDE_LEADING_SPACE
|| excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE
|| excluded == CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE;

const auto leadingAndTrailingSpacesFilesAllowed = !_discoveryData->_shouldEnforceWindowsFileNameCompatibility || _discoveryData->_leadingAndTrailingSpacesFilesAllowed.contains(_discoveryData->_localDir + path);
if (hasLeadingOrTrailingSpaces && (wasSyncedAlready || leadingAndTrailingSpacesFilesAllowed)) {
excluded = CSYNC_NOT_EXCLUDED;
Expand Down
75 changes: 75 additions & 0 deletions test/syncenginetestutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1207,6 +1207,81 @@ void FakeFolder::switchToVfs(QSharedPointer<OCC::Vfs> vfs)
vfs->start(vfsParams);
}

void FakeFolder::enableEnforceWindowsFileNameCompatibility()
{
syncEngine().account()->setCapabilities(QVariantMap{
{
"files",
QVariantMap{
{
"forbidden_filename_basenames",
QStringList{"con",
"prn",
"aux",
"nul",
"com0",
"com1",
"com2",
"com3",
"com4",
"com5",
"com6",
"com7",
"com8",
"com9",
"com¹",
"com²",
"com³",
"lpt0",
"lpt1",
"lpt2",
"lpt3",
"lpt4",
"lpt5",
"lpt6",
"lpt7",
"lpt8",
"lpt9",
"lpt¹",
"lpt²",
"lpt³"
}
},
{
"forbidden_filename_characters",
QStringList{"\\",
"/",
"<",
">",
":",
"\"",
"|",
"?",
"*",
"\\",
"/"
}
},
{
"forbidden_filename_extensions",
QStringList{" ",
".",
".filepart",
".part",
".part"
}
},
{
"forbidden_filenames",
QStringList{"\\",
".htaccess"
}
}
}
}
});
}

FileInfo FakeFolder::currentLocalState()
{
QDir rootDir { _tempDir.path() };
Expand Down
2 changes: 2 additions & 0 deletions test/syncenginetestutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,8 @@ class FakeFolder

void switchToVfs(QSharedPointer<OCC::Vfs> vfs);

void enableEnforceWindowsFileNameCompatibility();

[[nodiscard]] OCC::AccountPtr account() const { return _account; }
[[nodiscard]] OCC::SyncEngine &syncEngine() const { return *_syncEngine; }
[[nodiscard]] OCC::SyncJournalDb &syncJournal() const { return *_journalDb; }
Expand Down
5 changes: 5 additions & 0 deletions test/testlocaldiscovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,10 @@ private slots:
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile()
{
FakeFolder fakeFolder{FileInfo{}};
fakeFolder.enableEnforceWindowsFileNameCompatibility();

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

const QString fileWithSpaces1(" foo");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
Expand Down Expand Up @@ -459,6 +462,7 @@ private slots:
void testCreateLocalPathsWithLeadingAndTrailingSpaces_syncOnSupportingOs()
{
FakeFolder fakeFolder{FileInfo()};
fakeFolder.enableEnforceWindowsFileNameCompatibility();
fakeFolder.localModifier().mkdir("A");
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
Expand Down Expand Up @@ -541,6 +545,7 @@ private slots:
void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAutomaticallyAndDontUploadFile()
{
FakeFolder fakeFolder{FileInfo{}};
fakeFolder.enableEnforceWindowsFileNameCompatibility();
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces(" foo");
const QString fileTrimmed("foo");
Expand Down
2 changes: 2 additions & 0 deletions test/testsyncengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2039,6 +2039,8 @@ private slots:
void testCreateFileWithTrailingLeadingSpaces_local_automatedRenameBeforeUpload()
{
FakeFolder fakeFolder{FileInfo{}};
fakeFolder.enableEnforceWindowsFileNameCompatibility();

fakeFolder.syncEngine().setLocalDiscoveryEnforceWindowsFileNameCompatibility(true);

QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
Expand Down
76 changes: 70 additions & 6 deletions test/testsyncvirtualfiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -835,12 +835,21 @@ private slots:

QVERIFY(fakeFolder.syncOnce());

#if defined Q_OS_WINDOWS
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
#else
QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
#endif

fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces2);
Expand All @@ -853,12 +862,67 @@ private slots:

QVERIFY(fakeFolder.syncOnce());

QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
#if defined Q_OS_WINDOWS
QCOMPARE(completeSpy.findItem(QStringLiteral("foo"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("bar"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("bla"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("A/foo"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("A/bar"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("A/bla"))->_status, SyncFileItem::Status::Success);
#endif
}

void testCreateFileWithTrailingSpaces_acceptAndRejectInvalidFileName_enforceWindowsNamingRules()
{
FakeFolder fakeFolder{ FileInfo() };
fakeFolder.enableEnforceWindowsFileNameCompatibility();
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());

const QString fileWithSpaces1(" foo");
const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
const QString fileWithSpaces4("A/ foo");
const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");

fakeFolder.localModifier().insert(fileWithSpaces1);
fakeFolder.localModifier().insert(fileWithSpaces2);
fakeFolder.localModifier().insert(fileWithSpaces3);
fakeFolder.localModifier().mkdir("A");
fakeFolder.localModifier().insert(fileWithSpaces4);
fakeFolder.localModifier().insert(fileWithSpaces5);
fakeFolder.localModifier().insert(fileWithSpaces6);

ItemCompletedSpy completeSpy(fakeFolder);
completeSpy.clear();

QVERIFY(fakeFolder.syncOnce());

QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);

fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces2);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces3);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces4);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces5);
fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces6);

completeSpy.clear();

QVERIFY(fakeFolder.syncOnce());

QCOMPARE(completeSpy.findItem(QStringLiteral("foo"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("bar"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("bla"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("A/foo"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("A/bar"))->_status, SyncFileItem::Status::Success);
QCOMPARE(completeSpy.findItem(QStringLiteral("A/bla"))->_status, SyncFileItem::Status::Success);
}

void testCreateFileWithTrailingSpaces_remoteDontGetRenamedAutomatically()
Expand Down

0 comments on commit e8baa62

Please sign in to comment.