From 06b31d7cf07710c7b2435d761cc70b2e8f5a2059 Mon Sep 17 00:00:00 2001 From: Jenkins for ownCloud Date: Thu, 20 Nov 2014 01:25:20 -0500 Subject: [PATCH 1/3] [tx-robot] updated from transifex --- translations/mirall_fr.ts | 16 ++++++++-------- translations/mirall_tr.ts | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/translations/mirall_fr.ts b/translations/mirall_fr.ts index b615b7ce3..0ddb52915 100644 --- a/translations/mirall_fr.ts +++ b/translations/mirall_fr.ts @@ -37,7 +37,7 @@ Add Folder - Ajouter le dossier + Ajouter un dossier @@ -503,7 +503,7 @@ Voulez-vous réellement effectuer cette opération ? Add Folder - Ajouter le dossier + Ajouter un dossier @@ -1031,7 +1031,7 @@ peut demander des privilèges additionnels durant le processus. Connect to %1 - Connecter à %1 + Connexion à %1 @@ -1074,7 +1074,7 @@ peut demander des privilèges additionnels durant le processus. Connect to %1 - Connecter à %1 + Connexion à %1 @@ -1084,7 +1084,7 @@ peut demander des privilèges additionnels durant le processus. Update user credentials - Mettre à jour les identifiants de connexion de l'utilisateur + Modification des identifiants de connexion @@ -1092,7 +1092,7 @@ peut demander des privilèges additionnels durant le processus. Connect to %1 - Connecter à %1 + Connexion à %1 @@ -1132,7 +1132,7 @@ Voulez-vous vous connecter sans chiffrement à la place (non recommandé) ? Update %1 server - Mettre à jour le serveur %1 + Modification de l'adresse du serveur %1 @@ -2323,7 +2323,7 @@ Voulez-vous vous connecter sans chiffrement à la place (non recommandé) ? Sync everything from server - Synchroniser tout le contenu du serveur + Synchroniser tout le contenu de votre compte diff --git a/translations/mirall_tr.ts b/translations/mirall_tr.ts index b281002e4..1fcf3ab31 100644 --- a/translations/mirall_tr.ts +++ b/translations/mirall_tr.ts @@ -435,7 +435,7 @@ Bu işlemi gerçekleştirmek istediğinize emin misiniz? Waits to start syncing. - Eşitleme başlatmak için bekleniyor. + Eşitleme başlatmak için bekliyor. From 9dc57359b9e74ed6d8f74d17a72e00c73a67ce49 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Thu, 20 Nov 2014 12:30:04 +0100 Subject: [PATCH 2/3] csync db files: Hide after some commit/transactions. #2461 The shm and wal files are only created later. --- src/mirall/syncjournaldb.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mirall/syncjournaldb.cpp b/src/mirall/syncjournaldb.cpp index fca1c9e56..579bf575e 100644 --- a/src/mirall/syncjournaldb.cpp +++ b/src/mirall/syncjournaldb.cpp @@ -158,11 +158,6 @@ bool SyncJournalDb::checkConnect() return sqlFail("Set PRAGMA case_sensitivity", pragma1); } - // Hide 'em all! - FileSystem::setFileHidden(databaseFilePath(), true); - FileSystem::setFileHidden(databaseFilePath() + "-wal", true); - FileSystem::setFileHidden(databaseFilePath() + "-shm", true); - /* Because insert are so slow, e do everything in a transaction, and one need to call commit */ startTransaction(); @@ -335,6 +330,11 @@ bool SyncJournalDb::checkConnect() // don't start a new transaction now commitInternal(QString("checkConnect End"), false); + // Hide 'em all! + FileSystem::setFileHidden(databaseFilePath(), true); + FileSystem::setFileHidden(databaseFilePath() + "-wal", true); + FileSystem::setFileHidden(databaseFilePath() + "-shm", true); + return rc; } From d4e0941c2732508b2d944f19115c2c76c7eb593b Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Thu, 6 Nov 2014 00:36:04 +0100 Subject: [PATCH 3/3] Windows filewatcher: switch to ReadDirectoryChangesW. Based on danimo's #2454 fix for #2455 and related to #2297. --- src/mirall/folderwatcher_win.cpp | 132 ++++++++++++++++++++++++------- src/mirall/folderwatcher_win.h | 2 + test/testfolderwatcher.h | 96 ++++++++++++++++------ 3 files changed, 174 insertions(+), 56 deletions(-) diff --git a/src/mirall/folderwatcher_win.cpp b/src/mirall/folderwatcher_win.cpp index c6c8242fa..ced1c2d23 100644 --- a/src/mirall/folderwatcher_win.cpp +++ b/src/mirall/folderwatcher_win.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "mirall/folderwatcher.h" #include "mirall/folderwatcher_win.h" @@ -23,52 +24,123 @@ namespace Mirall { -void WatcherThread::run() +void WatcherThread::watchChanges(size_t fileNotifyBufferSize, + bool* increaseBufferSize) { - _handle = FindFirstChangeNotification((wchar_t*)_path.utf16(), - true, // recursive watch - FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_LAST_WRITE); + *increaseBufferSize = false; + + _handle = CreateFileW( + (wchar_t*)_path.utf16(), + FILE_LIST_DIRECTORY, + FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); if (_handle == INVALID_HANDLE_VALUE) { - qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification function failed, stopping watcher!"; - FindCloseChangeNotification(_handle); + DWORD errorCode = GetLastError(); + qDebug() << Q_FUNC_INFO << "Failed to create handle for" << _path << ", error:" << errorCode; _handle = 0; return; } - if (_handle == NULL) - { - qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned null, stopping watcher!"; - FindCloseChangeNotification(_handle); - _handle = 0; - return; - } + // QVarLengthArray ensures the stack-buffer is aligned like double and qint64. + QVarLengthArray fileNotifyBuffer; + fileNotifyBuffer.resize(fileNotifyBufferSize); - while(true) { - switch(WaitForSingleObject(_handle, /*wait*/ INFINITE)) { - case WAIT_OBJECT_0: - if (FindNextChangeNotification(_handle) == false) { - qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned FALSE, stopping watcher!"; - FindCloseChangeNotification(_handle); - _handle = 0; - return; + const size_t fileNameBufferSize = 4096; + TCHAR fileNameBuffer[fileNameBufferSize]; + + forever { + FILE_NOTIFY_INFORMATION *pFileNotifyBuffer = + (FILE_NOTIFY_INFORMATION*)fileNotifyBuffer.data(); + DWORD dwBytesReturned = 0; + SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize); + if(ReadDirectoryChangesW( _handle, (LPVOID)pFileNotifyBuffer, + fileNotifyBufferSize, true, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_LAST_WRITE, + &dwBytesReturned, NULL, NULL)) + { + FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer; + forever { + size_t len = curEntry->FileNameLength / 2; + QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, len); + + // Unless the file was removed or renamed, get its full long name + // TODO: We could still try expanding the path in the tricky cases... + QString longfile = file; + if (curEntry->Action != FILE_ACTION_REMOVED + && curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) { + size_t longNameSize = GetLongPathNameW(reinterpret_cast(file.utf16()), fileNameBuffer, fileNameBufferSize); + if (longNameSize > 0) { + longfile = QString::fromUtf16(reinterpret_cast(fileNameBuffer), longNameSize); + } else { + qDebug() << Q_FUNC_INFO << "Error converting file name to full length, keeping original name."; + } + } + longfile = QDir::cleanPath(longfile); + + qDebug() << Q_FUNC_INFO << "Found change in" << longfile << "action:" << curEntry->Action; + emit changed(longfile); + + if (curEntry->NextEntryOffset == 0) { + break; + } + curEntry = (FILE_NOTIFY_INFORMATION*)( + (char*)curEntry + curEntry->NextEntryOffset); } - // qDebug() << Q_FUNC_INFO << "Change detected in" << _path << "from" << QThread::currentThread (); - emit changed(_path); - break; - default: - qDebug() << Q_FUNC_INFO << "Error while watching"; + } else { + DWORD errorCode = GetLastError(); + switch(errorCode) { + case ERROR_NOTIFY_ENUM_DIR: + qDebug() << Q_FUNC_INFO << "The buffer for changes overflowed! Triggering a generic change and resizing"; + emit changed(_path); + *increaseBufferSize = true; + break; + default: + qDebug() << Q_FUNC_INFO << "General error" << errorCode << "while watching. Exiting."; + break; + } + CloseHandle(_handle); + _handle = NULL; + return; + } + } +} + +void WatcherThread::run() +{ + // If this buffer fills up before we've extracted its data we will lose + // change information. Therefore start big. + size_t bufferSize = 4096*10; + size_t maxBuffer = 64*1024; + + forever { + bool increaseBufferSize = false; + watchChanges(bufferSize, &increaseBufferSize); + + if (increaseBufferSize) { + bufferSize = qMin(bufferSize*2, maxBuffer); + } else { + // Other errors shouldn't actually happen, + // so sleep a bit to avoid running into the same error case in a + // tight loop. + sleep(2); } } } WatcherThread::~WatcherThread() { - if (_handle) - FindCloseChangeNotification(_handle); + if (_handle) { + CloseHandle(_handle); + _handle = NULL; + } } FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path) diff --git a/src/mirall/folderwatcher_win.h b/src/mirall/folderwatcher_win.h index 56ddfccd0..465477fd9 100644 --- a/src/mirall/folderwatcher_win.h +++ b/src/mirall/folderwatcher_win.h @@ -33,6 +33,8 @@ public: protected: void run(); + void watchChanges(size_t fileNotifyBufferSize, + bool* increaseBufferSize); signals: void changed(const QString &path); diff --git a/test/testfolderwatcher.h b/test/testfolderwatcher.h index 061a629ab..cc0584673 100644 --- a/test/testfolderwatcher.h +++ b/test/testfolderwatcher.h @@ -15,15 +15,23 @@ using namespace Mirall; +class FriendlyThread : public QThread +{ + friend class TestFolderWatcher; +}; + class TestFolderWatcher : public QObject { Q_OBJECT public slots: void slotFolderChanged( const QString& path ) { - qDebug() << "COMPARE: " << path << _checkMark; - QVERIFY(_checkMark == path); - _checkMark.clear(); + if (_skipNotifications.contains(path)) { + return; + } + if (_requiredNotifications.contains(path)) { + _receivedNotifications.insert(path); + } } void slotEnd() { // in case something goes wrong... @@ -36,7 +44,16 @@ private: FolderWatcher *_watcher; QEventLoop _loop; QTimer _timer; - QString _checkMark; + QSet _requiredNotifications; + QSet _receivedNotifications; + QSet _skipNotifications; + + void processAndWait() + { + _loop.processEvents(); + FriendlyThread::msleep(200); + _loop.processEvents(); + } private slots: void initTestCase() { @@ -52,68 +69,95 @@ private slots: rootDir.mkpath(_root + "/a2/b3/c3"); Utility::writeRandomFile( _root+"/a1/random.bin"); Utility::writeRandomFile( _root+"/a1/b2/todelete.bin"); - Utility::writeRandomFile( _root+"/a2/movefile"); + Utility::writeRandomFile( _root+"/a2/renamefile"); + Utility::writeRandomFile( _root+"/a1/movefile"); _watcher = new FolderWatcher(_root); QObject::connect(_watcher, SIGNAL(folderChanged(QString)), this, SLOT(slotFolderChanged(QString))); - _timer.singleShot(3000, this, SLOT(slotEnd())); + _timer.singleShot(5000, this, SLOT(slotEnd())); + } + + void init() + { + _receivedNotifications.clear(); + _requiredNotifications.clear(); + _skipNotifications.clear(); + } + + void checkNotifications() + { + processAndWait(); + QCOMPARE(_receivedNotifications, _requiredNotifications); } void testACreate() { // create a new file QString cmd; - _checkMark = _root; + _requiredNotifications.insert(_root); cmd = QString("echo \"xyz\" > %1/foo.txt").arg(_root); qDebug() << "Command: " << cmd; system(cmd.toLocal8Bit()); - _loop.processEvents(); - QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. + checkNotifications(); } void testATouch() { // touch an existing file. + _requiredNotifications.insert(_root+"/a1"); +#ifdef Q_OS_WIN + Utility::writeRandomFile(QString("%1/a1/random.bin").arg(_root)); +#else QString cmd; cmd = QString("/usr/bin/touch %1/a1/random.bin").arg(_root); - _checkMark = _root+"/a1"; qDebug() << "Command: " << cmd; system(cmd.toLocal8Bit()); +#endif - _loop.processEvents(); - QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. + checkNotifications(); } void testCreateADir() { - _checkMark = _root+"/a1/b1"; + _requiredNotifications.insert(_root+"/a1/b1"); + _skipNotifications.insert(_root + "/a1/b1/new_dir"); QDir dir; dir.mkdir( _root + "/a1/b1/new_dir"); QVERIFY(QFile::exists(_root + "/a1/b1/new_dir")); - _loop.processEvents(); - QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. + + checkNotifications(); } void testRemoveADir() { - _checkMark = _root+"/a1/b3"; + _requiredNotifications.insert(_root+"/a1/b3"); QDir dir; QVERIFY(dir.rmdir(_root+"/a1/b3/c3")); - _loop.processEvents(); - QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. + + checkNotifications(); } void testRemoveAFile() { - _checkMark = _root+"/a1/b2"; + _requiredNotifications.insert(_root+"/a1/b2"); QVERIFY(QFile::exists(_root+"/a1/b2/todelete.bin")); QFile::remove(_root+"/a1/b2/todelete.bin"); QVERIFY(!QFile::exists(_root+"/a1/b2/todelete.bin")); - _loop.processEvents(); - QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. + + checkNotifications(); + } + + void testRenameAFile() { + _requiredNotifications.insert(_root+"/a2"); + QVERIFY(QFile::exists(_root+"/a2/renamefile")); + QFile::rename(_root+"/a2/renamefile", _root+"/a2/renamefile.renamed" ); + QVERIFY(QFile::exists(_root+"/a2/renamefile.renamed")); + + checkNotifications(); } void testMoveAFile() { - _checkMark = _root+"/a2"; - QVERIFY(QFile::exists(_root+"/a2/movefile")); - QFile::rename(_root+"/a2/movefile", _root+"/a2/movefile.renamed" ); + _requiredNotifications.insert(_root+"/a1"); + _requiredNotifications.insert(_root+"/a2"); + QVERIFY(QFile::exists(_root+"/a1/movefile")); + QFile::rename(_root+"/a1/movefile", _root+"/a2/movefile.renamed" ); QVERIFY(QFile::exists(_root+"/a2/movefile.renamed")); - _loop.processEvents(); - QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. + + checkNotifications(); } void cleanupTestCase() {