Journal: Don't use a ._ path if it won't work #5633

When synchronizing a folder on a samba share, creating files that begin
with ._ is often forbidden. This prevented the client from creating
its ._sync_abcdef.db file.

Now, it'll check whether the preferred filename is creatable, and if
it isn't it'll use .sync_abcdef.db instead.

The disadvantage is that this alternative path won't be ignored by
older clients - that was the reason for the ._ prefix.
This commit is contained in:
Christian Kamm 2017-06-16 15:43:21 +02:00 committed by Markus Goetz
parent b50706a7aa
commit 4291ea47f7
8 changed files with 73 additions and 8 deletions

View file

@ -235,6 +235,11 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch
match = CSYNC_FILE_SILENTLY_EXCLUDED;
goto out;
}
rc = csync_fnmatch(".sync_*.db*", bname, 0);
if (rc == 0) {
match = CSYNC_FILE_SILENTLY_EXCLUDED;
goto out;
}
rc = csync_fnmatch(".csync_journal.db*", bname, 0);
if (rc == 0) {
match = CSYNC_FILE_SILENTLY_EXCLUDED;

View file

@ -157,7 +157,16 @@ static void check_csync_excluded(void **state)
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
rc = csync_excluded_no_ctx(csync->excludes, "subdir/._sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db.ctmp", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
rc = csync_excluded_no_ctx(csync->excludes, ".sync_5bdd60bdfcfa.db-shm", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
rc = csync_excluded_no_ctx(csync->excludes, "subdir/.sync_5bdd60bdfcfa.db", CSYNC_FTW_TYPE_FILE);
assert_int_equal(rc, CSYNC_FILE_SILENTLY_EXCLUDED);
/* pattern ]*.directory - ignore and remove */
rc = csync_excluded_no_ctx(csync->excludes, "my.~directory", CSYNC_FTW_TYPE_FILE);

View file

@ -469,7 +469,7 @@ restart_sync:
}
Cmd cmd;
QString dbPath = options.source_dir + SyncJournalDb::makeDbName(credentialFreeUrl, folder, user);
QString dbPath = options.source_dir + SyncJournalDb::makeDbName(options.source_dir, credentialFreeUrl, folder, user);
SyncJournalDb db(dbPath);
if (!selectiveSyncList.empty()) {

View file

@ -1003,7 +1003,7 @@ QString FolderDefinition::absoluteJournalPath() const
QString FolderDefinition::defaultJournalPath(AccountPtr account)
{
return SyncJournalDb::makeDbName(account->url(), targetPath, account->credentials()->user());
return SyncJournalDb::makeDbName(localPath, account->url(), targetPath, account->credentials()->user());
}
} // namespace OCC

View file

@ -235,11 +235,22 @@ void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account,
foreach (const auto& folderAlias, settings.childGroups()) {
FolderDefinition folderDefinition;
if (FolderDefinition::load(settings, folderAlias, &folderDefinition)) {
auto defaultJournalPath = folderDefinition.defaultJournalPath(account->account());
// Migration: Old settings don't have journalPath
if (folderDefinition.journalPath.isEmpty()) {
folderDefinition.journalPath = folderDefinition.defaultJournalPath(account->account());
folderDefinition.journalPath = defaultJournalPath;
}
folderDefinition.defaultJournalPath(account->account());
// Migration: ._ files sometimes don't work
// So if the configured journalPath is the default one ("._sync_*.db")
// but the current default doesn't have the underscore, switch to the
// new default. See SyncJournalDb::makeDbName().
if (folderDefinition.journalPath.startsWith("._sync_")
&& defaultJournalPath.startsWith(".sync_")) {
folderDefinition.journalPath = defaultJournalPath;
}
// Migration: If an old db is found, move it to the new name.
if (backwardsCompatible) {
SyncJournalDb::maybeMigrateDb(folderDefinition.localPath, folderDefinition.absoluteJournalPath());

View file

@ -171,7 +171,8 @@ void FolderWatcherPrivate::slotReceivedNotification(int fd)
// qDebug() << Q_FUNC_INFO << event->name;
if (fileName.startsWith("._sync_") ||
fileName.startsWith(".csync_journal.db") ||
fileName.startsWith(".owncloudsync.log")) {
fileName.startsWith(".owncloudsync.log") ||
fileName.startsWith(".sync_")) {
// qDebug() << "ignore journal";
} else {
const QString p = _watches[event->wd] + '/' + fileName;

View file

@ -17,6 +17,7 @@
#include <QDebug>
#include <QElapsedTimer>
#include <QUrl>
#include <QDir>
#include "ownsql.h"
@ -41,7 +42,8 @@ SyncJournalDb::SyncJournalDb(const QString& dbFilePath, QObject *parent) :
}
QString SyncJournalDb::makeDbName(const QUrl& remoteUrl,
QString SyncJournalDb::makeDbName(const QString& localPath,
const QUrl& remoteUrl,
const QString& remotePath,
const QString& user)
{
@ -56,6 +58,42 @@ QString SyncJournalDb::makeDbName(const QUrl& remoteUrl,
journalPath.append( ba.left(6).toHex() );
journalPath.append(".db");
// If the journal doesn't exist and we can't create a file
// at that location, try again with a journal name that doesn't
// have the ._ prefix.
//
// The disadvantage of that filename is that it will only be ignored
// by client versions >2.3.2.
//
// See #5633: "._*" is often forbidden on samba shared folders.
// If it exists already, the path is clearly usable
QFile file(QDir(localPath).filePath(journalPath));
if (file.exists()) {
return journalPath;
}
// Try to create a file there
if (file.open(QIODevice::ReadWrite)) {
// Ok, all good.
file.close();
file.remove();
return journalPath;
}
// Can we create it if we drop the underscore?
QString alternateJournalPath = journalPath.mid(2).prepend(".");
QFile file2(QDir(localPath).filePath(alternateJournalPath));
if (file2.open(QIODevice::ReadWrite)) {
// The alternative worked, use it
qDebug() << "Using alternate database path" << alternateJournalPath;
file2.close();
file2.remove();
return alternateJournalPath;
}
// Neither worked, just keep the original and throw errors later
qDebug() << "Could not find a writable database path" << file.fileName();
return journalPath;
}

View file

@ -41,7 +41,8 @@ public:
virtual ~SyncJournalDb();
/// Create a journal path for a specific configuration
static QString makeDbName(const QUrl& remoteUrl,
static QString makeDbName(const QString& localPath,
const QUrl& remoteUrl,
const QString& remotePath,
const QString& user);