Merge branch '1.7'

This commit is contained in:
Christian Kamm 2014-11-20 12:41:06 +01:00
commit f275002ebe
6 changed files with 188 additions and 70 deletions

View file

@ -13,6 +13,7 @@
#include <QThread> #include <QThread>
#include <QDebug> #include <QDebug>
#include <QDir>
#include "folderwatcher.h" #include "folderwatcher.h"
#include "folderwatcher_win.h" #include "folderwatcher_win.h"
@ -23,52 +24,123 @@
namespace Mirall { namespace Mirall {
void WatcherThread::run() void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
bool* increaseBufferSize)
{ {
_handle = FindFirstChangeNotification((wchar_t*)_path.utf16(), *increaseBufferSize = false;
true, // recursive watch
FILE_NOTIFY_CHANGE_FILE_NAME | _handle = CreateFileW(
FILE_NOTIFY_CHANGE_DIR_NAME | (wchar_t*)_path.utf16(),
FILE_NOTIFY_CHANGE_LAST_WRITE); 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) if (_handle == INVALID_HANDLE_VALUE)
{ {
qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification function failed, stopping watcher!"; DWORD errorCode = GetLastError();
FindCloseChangeNotification(_handle); qDebug() << Q_FUNC_INFO << "Failed to create handle for" << _path << ", error:" << errorCode;
_handle = 0; _handle = 0;
return; return;
} }
if (_handle == NULL) // QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
{ QVarLengthArray<char, 4096*10> fileNotifyBuffer;
qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned null, stopping watcher!"; fileNotifyBuffer.resize(fileNotifyBufferSize);
FindCloseChangeNotification(_handle);
_handle = 0;
return;
}
while(true) { const size_t fileNameBufferSize = 4096;
switch(WaitForSingleObject(_handle, /*wait*/ INFINITE)) { TCHAR fileNameBuffer[fileNameBufferSize];
case WAIT_OBJECT_0:
if (FindNextChangeNotification(_handle) == false) { forever {
qDebug() << Q_FUNC_INFO << "FindFirstChangeNotification returned FALSE, stopping watcher!"; FILE_NOTIFY_INFORMATION *pFileNotifyBuffer =
FindCloseChangeNotification(_handle); (FILE_NOTIFY_INFORMATION*)fileNotifyBuffer.data();
_handle = 0; DWORD dwBytesReturned = 0;
return; 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<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
if (longNameSize > 0) {
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(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 (); } else {
emit changed(_path); DWORD errorCode = GetLastError();
break; switch(errorCode) {
default: case ERROR_NOTIFY_ENUM_DIR:
qDebug() << Q_FUNC_INFO << "Error while watching"; 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() WatcherThread::~WatcherThread()
{ {
if (_handle) if (_handle) {
FindCloseChangeNotification(_handle); CloseHandle(_handle);
_handle = NULL;
}
} }
FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path) FolderWatcherPrivate::FolderWatcherPrivate(FolderWatcher *p, const QString& path)

View file

@ -33,6 +33,8 @@ public:
protected: protected:
void run(); void run();
void watchChanges(size_t fileNotifyBufferSize,
bool* increaseBufferSize);
signals: signals:
void changed(const QString &path); void changed(const QString &path);

View file

@ -158,11 +158,6 @@ bool SyncJournalDb::checkConnect()
return sqlFail("Set PRAGMA case_sensitivity", pragma1); 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 */ /* Because insert are so slow, e do everything in a transaction, and one need to call commit */
startTransaction(); startTransaction();
@ -349,6 +344,11 @@ bool SyncJournalDb::checkConnect()
// don't start a new transaction now // don't start a new transaction now
commitInternal(QString("checkConnect End"), false); commitInternal(QString("checkConnect End"), false);
// Hide 'em all!
FileSystem::setFileHidden(databaseFilePath(), true);
FileSystem::setFileHidden(databaseFilePath() + "-wal", true);
FileSystem::setFileHidden(databaseFilePath() + "-shm", true);
return rc; return rc;
} }

View file

@ -15,15 +15,23 @@
using namespace Mirall; using namespace Mirall;
class FriendlyThread : public QThread
{
friend class TestFolderWatcher;
};
class TestFolderWatcher : public QObject class TestFolderWatcher : public QObject
{ {
Q_OBJECT Q_OBJECT
public slots: public slots:
void slotFolderChanged( const QString& path ) { void slotFolderChanged( const QString& path ) {
qDebug() << "COMPARE: " << path << _checkMark; if (_skipNotifications.contains(path)) {
QVERIFY(_checkMark == path); return;
_checkMark.clear(); }
if (_requiredNotifications.contains(path)) {
_receivedNotifications.insert(path);
}
} }
void slotEnd() { // in case something goes wrong... void slotEnd() { // in case something goes wrong...
@ -36,7 +44,16 @@ private:
FolderWatcher *_watcher; FolderWatcher *_watcher;
QEventLoop _loop; QEventLoop _loop;
QTimer _timer; QTimer _timer;
QString _checkMark; QSet<QString> _requiredNotifications;
QSet<QString> _receivedNotifications;
QSet<QString> _skipNotifications;
void processAndWait()
{
_loop.processEvents();
FriendlyThread::msleep(200);
_loop.processEvents();
}
private slots: private slots:
void initTestCase() { void initTestCase() {
@ -52,68 +69,95 @@ private slots:
rootDir.mkpath(_root + "/a2/b3/c3"); rootDir.mkpath(_root + "/a2/b3/c3");
Utility::writeRandomFile( _root+"/a1/random.bin"); Utility::writeRandomFile( _root+"/a1/random.bin");
Utility::writeRandomFile( _root+"/a1/b2/todelete.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); _watcher = new FolderWatcher(_root);
QObject::connect(_watcher, SIGNAL(folderChanged(QString)), this, SLOT(slotFolderChanged(QString))); 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 void testACreate() { // create a new file
QString cmd; QString cmd;
_checkMark = _root; _requiredNotifications.insert(_root);
cmd = QString("echo \"xyz\" > %1/foo.txt").arg(_root); cmd = QString("echo \"xyz\" > %1/foo.txt").arg(_root);
qDebug() << "Command: " << cmd; qDebug() << "Command: " << cmd;
system(cmd.toLocal8Bit()); system(cmd.toLocal8Bit());
_loop.processEvents(); checkNotifications();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
} }
void testATouch() { // touch an existing file. 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; QString cmd;
cmd = QString("/usr/bin/touch %1/a1/random.bin").arg(_root); cmd = QString("/usr/bin/touch %1/a1/random.bin").arg(_root);
_checkMark = _root+"/a1";
qDebug() << "Command: " << cmd; qDebug() << "Command: " << cmd;
system(cmd.toLocal8Bit()); system(cmd.toLocal8Bit());
#endif
_loop.processEvents(); checkNotifications();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark.
} }
void testCreateADir() { void testCreateADir() {
_checkMark = _root+"/a1/b1"; _requiredNotifications.insert(_root+"/a1/b1");
_skipNotifications.insert(_root + "/a1/b1/new_dir");
QDir dir; QDir dir;
dir.mkdir( _root + "/a1/b1/new_dir"); dir.mkdir( _root + "/a1/b1/new_dir");
QVERIFY(QFile::exists(_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() { void testRemoveADir() {
_checkMark = _root+"/a1/b3"; _requiredNotifications.insert(_root+"/a1/b3");
QDir dir; QDir dir;
QVERIFY(dir.rmdir(_root+"/a1/b3/c3")); QVERIFY(dir.rmdir(_root+"/a1/b3/c3"));
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. checkNotifications();
} }
void testRemoveAFile() { void testRemoveAFile() {
_checkMark = _root+"/a1/b2"; _requiredNotifications.insert(_root+"/a1/b2");
QVERIFY(QFile::exists(_root+"/a1/b2/todelete.bin")); QVERIFY(QFile::exists(_root+"/a1/b2/todelete.bin"));
QFile::remove(_root+"/a1/b2/todelete.bin"); QFile::remove(_root+"/a1/b2/todelete.bin");
QVERIFY(!QFile::exists(_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() { void testMoveAFile() {
_checkMark = _root+"/a2"; _requiredNotifications.insert(_root+"/a1");
QVERIFY(QFile::exists(_root+"/a2/movefile")); _requiredNotifications.insert(_root+"/a2");
QFile::rename(_root+"/a2/movefile", _root+"/a2/movefile.renamed" ); QVERIFY(QFile::exists(_root+"/a1/movefile"));
QFile::rename(_root+"/a1/movefile", _root+"/a2/movefile.renamed" );
QVERIFY(QFile::exists(_root+"/a2/movefile.renamed")); QVERIFY(QFile::exists(_root+"/a2/movefile.renamed"));
_loop.processEvents();
QVERIFY(_checkMark.isEmpty()); // the slot clears the checkmark. checkNotifications();
} }
void cleanupTestCase() { void cleanupTestCase() {

View file

@ -37,7 +37,7 @@
<message> <message>
<location filename="../src/mirall/folderwizardtargetpage.ui" line="140"/> <location filename="../src/mirall/folderwizardtargetpage.ui" line="140"/>
<source>Add Folder</source> <source>Add Folder</source>
<translation>Ajouter le dossier</translation> <translation>Ajouter un dossier</translation>
</message> </message>
<message> <message>
<location filename="../src/mirall/folderwizardtargetpage.ui" line="160"/> <location filename="../src/mirall/folderwizardtargetpage.ui" line="160"/>
@ -503,7 +503,7 @@ Voulez-vous réellement effectuer cette opération ?</translation>
<location filename="../src/mirall/folderwizard.cpp" line="494"/> <location filename="../src/mirall/folderwizard.cpp" line="494"/>
<location filename="../src/mirall/folderwizard.cpp" line="496"/> <location filename="../src/mirall/folderwizard.cpp" line="496"/>
<source>Add Folder</source> <source>Add Folder</source>
<translation>Ajouter le dossier</translation> <translation>Ajouter un dossier</translation>
</message> </message>
</context> </context>
<context> <context>
@ -1031,7 +1031,7 @@ peut demander des privilèges additionnels durant le processus.</translation>
<message> <message>
<location filename="../src/wizard/owncloudadvancedsetuppage.cpp" line="49"/> <location filename="../src/wizard/owncloudadvancedsetuppage.cpp" line="49"/>
<source>Connect to %1</source> <source>Connect to %1</source>
<translation>Connecter à %1</translation> <translation>Connexion à %1</translation>
</message> </message>
<message> <message>
<location filename="../src/wizard/owncloudadvancedsetuppage.cpp" line="50"/> <location filename="../src/wizard/owncloudadvancedsetuppage.cpp" line="50"/>
@ -1074,7 +1074,7 @@ peut demander des privilèges additionnels durant le processus.</translation>
<message> <message>
<location filename="../src/wizard/owncloudhttpcredspage.cpp" line="42"/> <location filename="../src/wizard/owncloudhttpcredspage.cpp" line="42"/>
<source>Connect to %1</source> <source>Connect to %1</source>
<translation>Connecter à %1</translation> <translation>Connexion à %1</translation>
</message> </message>
<message> <message>
<location filename="../src/wizard/owncloudhttpcredspage.cpp" line="43"/> <location filename="../src/wizard/owncloudhttpcredspage.cpp" line="43"/>
@ -1084,7 +1084,7 @@ peut demander des privilèges additionnels durant le processus.</translation>
<message> <message>
<location filename="../src/wizard/owncloudhttpcredspage.cpp" line="159"/> <location filename="../src/wizard/owncloudhttpcredspage.cpp" line="159"/>
<source>Update user credentials</source> <source>Update user credentials</source>
<translation>Mettre à jour les identifiants de connexion de l&apos;utilisateur</translation> <translation>Modification des identifiants de connexion</translation>
</message> </message>
</context> </context>
<context> <context>
@ -1092,7 +1092,7 @@ peut demander des privilèges additionnels durant le processus.</translation>
<message> <message>
<location filename="../src/wizard/owncloudsetuppage.cpp" line="45"/> <location filename="../src/wizard/owncloudsetuppage.cpp" line="45"/>
<source>Connect to %1</source> <source>Connect to %1</source>
<translation>Connecter à %1</translation> <translation>Connexion à %1</translation>
</message> </message>
<message> <message>
<location filename="../src/wizard/owncloudsetuppage.cpp" line="46"/> <location filename="../src/wizard/owncloudsetuppage.cpp" line="46"/>
@ -1132,7 +1132,7 @@ Voulez-vous vous connecter sans chiffrement à la place (non recommandé) ?</tra
<message> <message>
<location filename="../src/wizard/owncloudsetuppage.cpp" line="263"/> <location filename="../src/wizard/owncloudsetuppage.cpp" line="263"/>
<source>Update %1 server</source> <source>Update %1 server</source>
<translation>Mettre à jour le serveur %1</translation> <translation>Modification de l&apos;adresse du serveur %1</translation>
</message> </message>
</context> </context>
<context> <context>
@ -2323,7 +2323,7 @@ Voulez-vous vous connecter sans chiffrement à la place (non recommandé) ?</tra
<message> <message>
<location filename="../src/wizard/owncloudadvancedsetuppage.ui" line="103"/> <location filename="../src/wizard/owncloudadvancedsetuppage.ui" line="103"/>
<source>Sync everything from server</source> <source>Sync everything from server</source>
<translation>Synchroniser tout le contenu du serveur</translation> <translation>Synchroniser tout le contenu de votre compte</translation>
</message> </message>
<message> <message>
<location filename="../src/wizard/owncloudadvancedsetuppage.ui" line="122"/> <location filename="../src/wizard/owncloudadvancedsetuppage.ui" line="122"/>

View file

@ -435,7 +435,7 @@ Bu işlemi gerçekleştirmek istediğinize emin misiniz?</translation>
<message> <message>
<location filename="../src/mirall/folderman.cpp" line="873"/> <location filename="../src/mirall/folderman.cpp" line="873"/>
<source>Waits to start syncing.</source> <source>Waits to start syncing.</source>
<translation>Eşitleme başlatmak için bekleniyor.</translation> <translation>Eşitleme başlatmak için bekliyor.</translation>
</message> </message>
<message> <message>
<location filename="../src/mirall/folderman.cpp" line="876"/> <location filename="../src/mirall/folderman.cpp" line="876"/>