2013-10-03 17:27:29 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <QFile>
|
|
|
|
#include <QStringList>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QSqlError>
|
|
|
|
#include <QSqlQuery>
|
|
|
|
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
|
|
|
#include "syncjournaldb.h"
|
|
|
|
#include "syncjournalfilerecord.h"
|
2014-01-29 14:39:14 +04:00
|
|
|
#include "utility.h"
|
2014-04-25 15:31:44 +04:00
|
|
|
#include "version.h"
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2014-01-15 15:20:03 +04:00
|
|
|
#include "../../csync/src/std/c_jhash.h"
|
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
#define QSQLITE "QSQLITE"
|
2013-10-03 17:27:29 +04:00
|
|
|
|
|
|
|
namespace Mirall {
|
|
|
|
|
|
|
|
SyncJournalDb::SyncJournalDb(const QString& path, QObject *parent) :
|
2014-04-25 15:31:44 +04:00
|
|
|
QObject(parent), _transaction(0), _possibleUpgradeFromMirall_1_5(false)
|
2013-10-03 17:27:29 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
_dbFile = path;
|
|
|
|
if( !_dbFile.endsWith('/') ) {
|
|
|
|
_dbFile.append('/');
|
|
|
|
}
|
|
|
|
_dbFile.append(".csync_journal.db");
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2013-10-04 16:44:57 +04:00
|
|
|
bool SyncJournalDb::exists()
|
|
|
|
{
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2013-10-04 16:44:57 +04:00
|
|
|
return (!_dbFile.isEmpty() && QFile::exists(_dbFile));
|
|
|
|
}
|
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
void SyncJournalDb::startTransaction()
|
|
|
|
{
|
|
|
|
if( _transaction == 0 ) {
|
|
|
|
if( !_db.transaction() ) {
|
2013-12-09 23:17:56 +04:00
|
|
|
qDebug() << "ERROR committing to the database: " << _db.lastError().text();
|
2013-11-21 14:13:58 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
_transaction = 1;
|
|
|
|
// qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Transaction start!";
|
|
|
|
} else {
|
|
|
|
qDebug() << "Database Transaction is running, do not starting another one!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::commitTransaction()
|
|
|
|
{
|
|
|
|
if( _transaction == 1 ) {
|
|
|
|
if( ! _db.commit() ) {
|
2013-12-09 23:17:56 +04:00
|
|
|
qDebug() << "ERROR committing to the database: " << _db.lastError().text();
|
2013-11-21 14:13:58 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
_transaction = 0;
|
|
|
|
// qDebug() << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Transaction END!";
|
|
|
|
} else {
|
|
|
|
qDebug() << "No database Transaction to commit";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SyncJournalDb::sqlFail( const QString& log, const QSqlQuery& query )
|
|
|
|
{
|
|
|
|
commitTransaction();
|
|
|
|
qWarning() << "Error" << log << query.lastError().text();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
bool SyncJournalDb::checkConnect()
|
|
|
|
{
|
|
|
|
if( _db.isOpen() ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( _dbFile.isEmpty() || !QFile::exists(_dbFile) ) {
|
2014-03-26 19:40:00 +04:00
|
|
|
qDebug() << "Database " + _dbFile + " is empty or does not exist";
|
2013-10-03 17:27:29 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList list = QSqlDatabase::drivers();
|
|
|
|
if( list.size() == 0 ) {
|
|
|
|
qDebug() << "Database Drivers could not be loaded.";
|
|
|
|
return false ;
|
|
|
|
} else {
|
|
|
|
if( list.indexOf( QSQLITE ) == -1 ) {
|
|
|
|
qDebug() << "Database Driver QSQLITE could not be loaded!";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-19 14:28:08 +04:00
|
|
|
// Add the connection
|
2013-11-25 18:07:58 +04:00
|
|
|
_db = QSqlDatabase::addDatabase( QSQLITE, _dbFile);
|
2013-11-19 14:28:08 +04:00
|
|
|
|
|
|
|
// Open the file
|
2013-10-03 21:52:09 +04:00
|
|
|
_db.setDatabaseName(_dbFile);
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-10-03 21:52:09 +04:00
|
|
|
if (!_db.isOpen()) {
|
|
|
|
if( !_db.open() ) {
|
|
|
|
QSqlError error = _db.lastError();
|
|
|
|
qDebug() << "Error opening the db: " << error.text();
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
QSqlQuery pragma1(_db);
|
|
|
|
pragma1.prepare("PRAGMA synchronous = 1;");
|
|
|
|
if (!pragma1.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Set PRAGMA synchronous", pragma1);
|
2013-11-18 13:02:15 +04:00
|
|
|
}
|
|
|
|
pragma1.prepare("PRAGMA case_sensitive_like = ON;");
|
|
|
|
if (!pragma1.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Set PRAGMA case_sensitivity", pragma1);
|
2013-11-18 13:02:15 +04:00
|
|
|
}
|
2013-10-04 00:41:12 +04:00
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
/* Because insert are so slow, e do everything in a transaction, and one need to call commit */
|
2013-11-21 14:13:58 +04:00
|
|
|
startTransaction();
|
2013-11-18 13:02:15 +04:00
|
|
|
|
|
|
|
QSqlQuery createQuery(_db);
|
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS metadata("
|
|
|
|
"phash INTEGER(8),"
|
|
|
|
"pathlen INTEGER,"
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"inode INTEGER,"
|
|
|
|
"uid INTEGER,"
|
|
|
|
"gid INTEGER,"
|
|
|
|
"mode INTEGER,"
|
|
|
|
"modtime INTEGER(8),"
|
|
|
|
"type INTEGER,"
|
|
|
|
"md5 VARCHAR(32)," /* This is the etag. Called md5 for compatibility */
|
2014-06-06 17:24:17 +04:00
|
|
|
// updateDatabaseStructure() will add a fileid column
|
|
|
|
// updateDatabaseStructure() will add a remotePerm column
|
2013-11-18 13:02:15 +04:00
|
|
|
"PRIMARY KEY(phash)"
|
|
|
|
");");
|
|
|
|
|
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table metadata", createQuery);
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS downloadinfo("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"tmpfile VARCHAR(4096),"
|
|
|
|
"etag VARCHAR(32),"
|
|
|
|
"errorcount INTEGER,"
|
|
|
|
"PRIMARY KEY(path)"
|
|
|
|
");");
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table downloadinfo", createQuery);
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS uploadinfo("
|
2013-10-16 13:59:54 +04:00
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"chunk INTEGER,"
|
|
|
|
"transferid INTEGER,"
|
|
|
|
"errorcount INTEGER,"
|
|
|
|
"size INTEGER(8),"
|
|
|
|
"modtime INTEGER(8),"
|
|
|
|
"PRIMARY KEY(path)"
|
2013-11-18 13:02:15 +04:00
|
|
|
");");
|
2013-10-04 00:41:12 +04:00
|
|
|
|
2013-11-18 13:02:15 +04:00
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table uploadinfo", createQuery);
|
2013-11-15 20:42:48 +04:00
|
|
|
}
|
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
// create the blacklist table.
|
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS blacklist ("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"lastTryEtag VARCHAR[32],"
|
|
|
|
"lastTryModtime INTEGER[8],"
|
2013-11-21 14:13:58 +04:00
|
|
|
"retrycount INTEGER,"
|
2013-11-20 16:44:01 +04:00
|
|
|
"errorstring VARCHAR[4096],"
|
|
|
|
"PRIMARY KEY(path)"
|
|
|
|
");");
|
|
|
|
|
|
|
|
if (!createQuery.exec()) {
|
2013-11-21 14:13:58 +04:00
|
|
|
return sqlFail("Create table blacklist", createQuery);
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
|
2014-07-28 14:12:52 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS poll("
|
|
|
|
"path VARCHAR(4096),"
|
|
|
|
"modtime INTEGER(8),"
|
|
|
|
"pollpath VARCHAR(4096));");
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Create table poll", createQuery);
|
|
|
|
}
|
|
|
|
|
2014-04-25 15:31:44 +04:00
|
|
|
createQuery.prepare("CREATE TABLE IF NOT EXISTS version("
|
|
|
|
"major INTEGER(8),"
|
|
|
|
"minor INTEGER(8),"
|
|
|
|
"patch INTEGER(8),"
|
|
|
|
"custom VARCHAR(256)"
|
|
|
|
");");
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Create table blacklist", createQuery);
|
|
|
|
}
|
|
|
|
|
|
|
|
QSqlQuery versionQuery("SELECT major, minor FROM version;", _db);
|
|
|
|
if (!versionQuery.next()) {
|
|
|
|
// If there was no entry in the table, it means we are likely upgrading from 1.5
|
|
|
|
_possibleUpgradeFromMirall_1_5 = true;
|
|
|
|
} else {
|
|
|
|
// Delete the existing entry so we can replace it by the new one
|
|
|
|
createQuery.prepare("DELETE FROM version;");
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Remove version", createQuery);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
createQuery.prepare("INSERT INTO version (major, minor, patch) VALUES ( ? , ? , ? );");
|
|
|
|
createQuery.bindValue(0, MIRALL_VERSION_MAJOR);
|
|
|
|
createQuery.bindValue(1, MIRALL_VERSION_MINOR);
|
|
|
|
createQuery.bindValue(2, MIRALL_VERSION_PATCH);
|
|
|
|
if (!createQuery.exec()) {
|
|
|
|
return sqlFail("Insert Version", createQuery);
|
|
|
|
}
|
|
|
|
|
2013-11-25 18:11:37 +04:00
|
|
|
commitInternal("checkConnect");
|
2013-11-21 14:13:58 +04:00
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
bool rc = updateDatabaseStructure();
|
2013-11-15 14:21:27 +04:00
|
|
|
if( rc ) {
|
|
|
|
_getFileRecordQuery.reset(new QSqlQuery(_db));
|
2014-06-06 17:24:17 +04:00
|
|
|
_getFileRecordQuery->prepare("SELECT path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm FROM "
|
2013-11-15 14:21:27 +04:00
|
|
|
"metadata WHERE phash=:ph" );
|
|
|
|
|
|
|
|
_setFileRecordQuery.reset(new QSqlQuery(_db) );
|
|
|
|
_setFileRecordQuery->prepare("INSERT OR REPLACE INTO metadata "
|
2014-06-06 17:24:17 +04:00
|
|
|
"(phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid, remotePerm) "
|
|
|
|
"VALUES ( ? , ?, ? , ? , ? , ? , ?, ? , ? , ?, ?, ? )" );
|
2013-11-15 14:21:27 +04:00
|
|
|
|
|
|
|
_getDownloadInfoQuery.reset(new QSqlQuery(_db) );
|
|
|
|
_getDownloadInfoQuery->prepare( "SELECT tmpfile, etag, errorcount FROM "
|
|
|
|
"downloadinfo WHERE path=:pa" );
|
|
|
|
|
|
|
|
_setDownloadInfoQuery.reset(new QSqlQuery(_db) );
|
|
|
|
_setDownloadInfoQuery->prepare( "INSERT OR REPLACE INTO downloadinfo "
|
|
|
|
"(path, tmpfile, etag, errorcount) "
|
|
|
|
"VALUES ( ? , ?, ? , ? )" );
|
|
|
|
|
|
|
|
_deleteDownloadInfoQuery.reset(new QSqlQuery(_db) );
|
|
|
|
_deleteDownloadInfoQuery->prepare( "DELETE FROM downloadinfo WHERE path=?" );
|
|
|
|
|
|
|
|
_getUploadInfoQuery.reset(new QSqlQuery(_db));
|
|
|
|
_getUploadInfoQuery->prepare( "SELECT chunk, transferid, errorcount, size, modtime FROM "
|
|
|
|
"uploadinfo WHERE path=:pa" );
|
|
|
|
|
|
|
|
_setUploadInfoQuery.reset(new QSqlQuery(_db));
|
|
|
|
_setUploadInfoQuery->prepare( "INSERT OR REPLACE INTO uploadinfo "
|
|
|
|
"(path, chunk, transferid, errorcount, size, modtime) "
|
|
|
|
"VALUES ( ? , ?, ? , ? , ? , ? )");
|
|
|
|
|
|
|
|
_deleteUploadInfoQuery.reset(new QSqlQuery(_db));
|
|
|
|
_deleteUploadInfoQuery->prepare("DELETE FROM uploadinfo WHERE path=?" );
|
2013-11-18 16:02:09 +04:00
|
|
|
|
|
|
|
|
|
|
|
_deleteFileRecordPhash.reset(new QSqlQuery(_db));
|
|
|
|
_deleteFileRecordPhash->prepare("DELETE FROM metadata WHERE phash=?");
|
|
|
|
|
|
|
|
_deleteFileRecordRecursively.reset(new QSqlQuery(_db));
|
|
|
|
_deleteFileRecordRecursively->prepare("DELETE FROM metadata WHERE path LIKE(?||'/%')");
|
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
_blacklistQuery.reset(new QSqlQuery(_db));
|
|
|
|
_blacklistQuery->prepare("SELECT lastTryEtag, lastTryModtime, retrycount, errorstring "
|
|
|
|
"FROM blacklist WHERE path=:path");
|
2013-11-15 14:21:27 +04:00
|
|
|
}
|
2013-10-25 15:30:45 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-11-18 12:58:02 +04:00
|
|
|
void SyncJournalDb::close()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
commitTransaction();
|
|
|
|
|
2013-11-18 12:58:02 +04:00
|
|
|
_getFileRecordQuery.reset(0);
|
|
|
|
_setFileRecordQuery.reset(0);
|
|
|
|
_getDownloadInfoQuery.reset(0);
|
|
|
|
_setDownloadInfoQuery.reset(0);
|
|
|
|
_deleteDownloadInfoQuery.reset(0);
|
|
|
|
_getUploadInfoQuery.reset(0);
|
|
|
|
_setUploadInfoQuery.reset(0);
|
|
|
|
_deleteUploadInfoQuery.reset(0);
|
2013-11-18 16:02:09 +04:00
|
|
|
_deleteFileRecordPhash.reset(0);
|
|
|
|
_deleteFileRecordRecursively.reset(0);
|
2013-11-20 16:44:01 +04:00
|
|
|
_blacklistQuery.reset(0);
|
2014-04-25 15:31:44 +04:00
|
|
|
_possibleUpgradeFromMirall_1_5 = false;
|
2013-11-20 21:19:14 +04:00
|
|
|
|
2013-11-18 12:58:02 +04:00
|
|
|
_db.close();
|
2013-11-25 18:07:58 +04:00
|
|
|
_db = QSqlDatabase(); // avoid the warning QSqlDatabasePrivate::removeDatabase: connection [...] still in use
|
|
|
|
QSqlDatabase::removeDatabase(_dbFile);
|
2014-08-07 14:10:32 +04:00
|
|
|
_avoidReadFromDbOnNextSyncFilter.clear();
|
2013-11-18 12:58:02 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
bool SyncJournalDb::updateDatabaseStructure()
|
|
|
|
{
|
|
|
|
QStringList columns = tableColumns("metadata");
|
2013-11-20 16:44:01 +04:00
|
|
|
bool re = true;
|
2013-10-25 15:30:45 +04:00
|
|
|
|
|
|
|
// check if the file_id column is there and create it if not
|
2013-11-21 14:13:58 +04:00
|
|
|
if( !checkConnect() ) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-10-25 15:30:45 +04:00
|
|
|
if( columns.indexOf(QLatin1String("fileid")) == -1 ) {
|
2013-11-21 14:13:58 +04:00
|
|
|
|
2013-11-18 16:02:09 +04:00
|
|
|
QSqlQuery query(_db);
|
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN fileid VARCHAR(128);");
|
2013-11-20 16:44:01 +04:00
|
|
|
re = query.exec();
|
2013-11-18 16:02:09 +04:00
|
|
|
|
|
|
|
query.prepare("CREATE INDEX metadata_file_id ON metadata(fileid);");
|
2013-11-20 16:44:01 +04:00
|
|
|
re = re && query.exec();
|
2013-11-21 14:13:58 +04:00
|
|
|
|
2013-11-25 18:11:37 +04:00
|
|
|
commitInternal("update database structure");
|
2013-10-25 15:30:45 +04:00
|
|
|
}
|
2014-06-06 17:24:17 +04:00
|
|
|
if( columns.indexOf(QLatin1String("remotePerm")) == -1 ) {
|
|
|
|
|
|
|
|
QSqlQuery query(_db);
|
|
|
|
query.prepare("ALTER TABLE metadata ADD COLUMN remotePerm VARCHAR(128);");
|
|
|
|
re = query.exec();
|
|
|
|
commitInternal("update database structure (remotePerm");
|
|
|
|
}
|
2013-11-20 16:44:01 +04:00
|
|
|
|
|
|
|
return re;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2013-10-25 15:30:45 +04:00
|
|
|
QStringList SyncJournalDb::tableColumns( const QString& table )
|
|
|
|
{
|
|
|
|
QStringList columns;
|
|
|
|
if( !table.isEmpty() ) {
|
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
if( checkConnect() ) {
|
|
|
|
QString q = QString("PRAGMA table_info(%1);").arg(table);
|
|
|
|
QSqlQuery query(_db);
|
|
|
|
query.prepare(q);
|
2013-10-25 15:30:45 +04:00
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
if(!query.exec()) {
|
|
|
|
QString err = query.lastError().text();
|
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;;
|
|
|
|
return columns;
|
|
|
|
}
|
2013-10-25 15:30:45 +04:00
|
|
|
|
2013-11-21 14:13:58 +04:00
|
|
|
while( query.next() ) {
|
|
|
|
columns.append( query.value(1).toString() );
|
|
|
|
}
|
2013-10-25 15:30:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qDebug() << "Columns in the current journal: " << columns;
|
|
|
|
|
|
|
|
return columns;
|
|
|
|
}
|
|
|
|
|
2013-10-04 22:29:42 +04:00
|
|
|
qint64 SyncJournalDb::getPHash(const QString& file) const
|
2013-10-03 17:27:29 +04:00
|
|
|
{
|
|
|
|
QByteArray utf8File = file.toUtf8();
|
2013-10-03 20:52:02 +04:00
|
|
|
int64_t h;
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-10-03 19:48:04 +04:00
|
|
|
if( file.isEmpty() ) {
|
2013-10-03 20:52:02 +04:00
|
|
|
return -1;
|
2013-10-03 19:48:04 +04:00
|
|
|
}
|
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
int len = utf8File.length();
|
|
|
|
|
|
|
|
h = c_jhash64((uint8_t *) utf8File.data(), len, 0);
|
2013-10-03 20:52:02 +04:00
|
|
|
return h;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
|
2014-08-07 14:10:32 +04:00
|
|
|
bool SyncJournalDb::setFileRecord( const SyncJournalFileRecord& _record )
|
2013-10-03 19:48:04 +04:00
|
|
|
{
|
2014-08-07 14:10:32 +04:00
|
|
|
SyncJournalFileRecord record = _record;
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2014-08-07 14:10:32 +04:00
|
|
|
|
|
|
|
if (!_avoidReadFromDbOnNextSyncFilter.isEmpty()) {
|
|
|
|
// If we are a directory that should not be read from db next time, don't write the etag
|
|
|
|
QString prefix = record._path + "/";
|
|
|
|
foreach(const QString &it, _avoidReadFromDbOnNextSyncFilter) {
|
|
|
|
if (it.startsWith(prefix)) {
|
|
|
|
qDebug() << "Filtered writing the etag of" << prefix << "because it is a prefix of" << it;
|
|
|
|
record._etag = "_invalid_";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
qlonglong phash = getPHash(record._path);
|
2013-10-03 19:48:04 +04:00
|
|
|
if( checkConnect() ) {
|
2013-10-04 00:41:12 +04:00
|
|
|
QByteArray arr = record._path.toUtf8();
|
|
|
|
int plen = arr.length();
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
QString etag( record._etag );
|
|
|
|
if( etag.isEmpty() ) etag = "";
|
|
|
|
QString fileId( record._fileId);
|
|
|
|
if( fileId.isEmpty() ) fileId = "";
|
2014-06-06 17:24:17 +04:00
|
|
|
QString remotePerm (record._remotePerm);
|
2014-06-06 19:05:55 +04:00
|
|
|
if (remotePerm.isEmpty()) remotePerm = QString(); // have NULL in DB (vs empty)
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
_setFileRecordQuery->bindValue(0, QString::number(phash));
|
|
|
|
_setFileRecordQuery->bindValue(1, plen);
|
|
|
|
_setFileRecordQuery->bindValue(2, record._path );
|
|
|
|
_setFileRecordQuery->bindValue(3, record._inode );
|
2014-06-04 18:01:05 +04:00
|
|
|
_setFileRecordQuery->bindValue(4, 0 ); // uid Not used
|
|
|
|
_setFileRecordQuery->bindValue(5, 0 ); // gid Not used
|
2013-11-13 14:16:00 +04:00
|
|
|
_setFileRecordQuery->bindValue(6, record._mode );
|
2014-01-29 14:39:14 +04:00
|
|
|
_setFileRecordQuery->bindValue(7, QString::number(Utility::qDateTimeToTime_t(record._modtime)));
|
2013-11-13 14:16:00 +04:00
|
|
|
_setFileRecordQuery->bindValue(8, QString::number(record._type) );
|
|
|
|
_setFileRecordQuery->bindValue(9, etag );
|
|
|
|
_setFileRecordQuery->bindValue(10, fileId );
|
2014-06-06 17:24:17 +04:00
|
|
|
_setFileRecordQuery->bindValue(11, remotePerm );
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
if( !_setFileRecordQuery->exec() ) {
|
|
|
|
qWarning() << "Error SQL statement setFileRecord: " << _setFileRecordQuery->lastQuery() << " :"
|
|
|
|
<< _setFileRecordQuery->lastError().text();
|
2013-10-04 00:41:12 +04:00
|
|
|
return false;
|
2013-10-03 19:48:04 +04:00
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _setFileRecordQuery->lastQuery() << phash << plen << record._path << record._inode
|
2014-06-04 18:01:05 +04:00
|
|
|
<< record._mode
|
2014-01-29 14:39:14 +04:00
|
|
|
<< QString::number(Utility::qDateTimeToTime_t(record._modtime)) << QString::number(record._type)
|
2014-06-06 17:24:17 +04:00
|
|
|
<< record._etag << record._fileId << record._remotePerm;
|
2013-11-13 14:16:00 +04:00
|
|
|
_setFileRecordQuery->finish();
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
qDebug() << "Failed to connect database.";
|
|
|
|
return false; // checkConnect failed.
|
|
|
|
}
|
|
|
|
}
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-10-28 13:47:10 +04:00
|
|
|
bool SyncJournalDb::deleteFileRecord(const QString& filename, bool recursively)
|
2013-10-04 00:41:12 +04:00
|
|
|
{
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
2013-10-03 19:48:04 +04:00
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
if( checkConnect() ) {
|
2013-12-06 19:37:30 +04:00
|
|
|
// if (!recursively) {
|
|
|
|
// always delete the actual file.
|
|
|
|
|
|
|
|
qlonglong phash = getPHash(filename);
|
|
|
|
_deleteFileRecordPhash->bindValue( 0, QString::number(phash) );
|
|
|
|
|
|
|
|
if( !_deleteFileRecordPhash->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: "
|
|
|
|
<< _deleteFileRecordPhash->lastQuery()
|
|
|
|
<< " : " << _deleteFileRecordPhash->lastError().text();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
qDebug() << _deleteFileRecordPhash->executedQuery() << phash << filename;
|
|
|
|
_deleteFileRecordPhash->finish();
|
|
|
|
if( recursively) {
|
2013-11-18 16:02:09 +04:00
|
|
|
_deleteFileRecordRecursively->bindValue(0, filename);
|
|
|
|
if( !_deleteFileRecordRecursively->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: "
|
|
|
|
<< _deleteFileRecordRecursively->lastQuery()
|
|
|
|
<< " : " << _deleteFileRecordRecursively->lastError().text();
|
2013-10-28 13:47:10 +04:00
|
|
|
return false;
|
|
|
|
}
|
2013-11-18 16:02:09 +04:00
|
|
|
qDebug() << _deleteFileRecordRecursively->executedQuery() << filename;
|
|
|
|
_deleteFileRecordRecursively->finish();
|
2013-10-03 19:48:04 +04:00
|
|
|
}
|
2013-11-18 16:02:09 +04:00
|
|
|
return true;
|
2013-10-03 19:48:04 +04:00
|
|
|
} else {
|
|
|
|
qDebug() << "Failed to connect database.";
|
|
|
|
return false; // checkConnect failed.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-04 00:41:12 +04:00
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
|
|
|
|
{
|
2013-10-04 23:02:23 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-10-03 21:52:09 +04:00
|
|
|
qlonglong phash = getPHash( filename );
|
2013-10-03 17:27:29 +04:00
|
|
|
SyncJournalFileRecord rec;
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
2013-11-13 14:16:00 +04:00
|
|
|
_getFileRecordQuery->bindValue(":ph", QString::number(phash));
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if (!_getFileRecordQuery->exec()) {
|
|
|
|
QString err = _getFileRecordQuery->lastError().text();
|
|
|
|
qDebug() << "Error creating prepared statement: " << _getFileRecordQuery->lastQuery() << ", Error:" << err;;
|
2013-10-03 21:52:09 +04:00
|
|
|
return rec;
|
|
|
|
}
|
2013-10-03 17:27:29 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( _getFileRecordQuery->next() ) {
|
2013-10-03 20:52:02 +04:00
|
|
|
bool ok;
|
2013-11-13 14:16:00 +04:00
|
|
|
rec._path = _getFileRecordQuery->value(0).toString();
|
|
|
|
rec._inode = _getFileRecordQuery->value(1).toInt(&ok);
|
2014-06-04 18:01:05 +04:00
|
|
|
//rec._uid = _getFileRecordQuery->value(2).toInt(&ok); Not Used
|
|
|
|
//rec._gid = _getFileRecordQuery->value(3).toInt(&ok); Not Used
|
2013-11-13 14:16:00 +04:00
|
|
|
rec._mode = _getFileRecordQuery->value(4).toInt(&ok);
|
2014-01-29 14:39:14 +04:00
|
|
|
rec._modtime = Utility::qDateTimeFromTime_t(_getFileRecordQuery->value(5).toLongLong(&ok));
|
2013-11-13 14:16:00 +04:00
|
|
|
rec._type = _getFileRecordQuery->value(6).toInt(&ok);
|
|
|
|
rec._etag = _getFileRecordQuery->value(7).toString();
|
|
|
|
rec._fileId = _getFileRecordQuery->value(8).toString();
|
2014-06-06 17:24:17 +04:00
|
|
|
rec._remotePerm = _getFileRecordQuery->value(9).toByteArray();
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
_getFileRecordQuery->finish();
|
2013-10-03 20:52:02 +04:00
|
|
|
} else {
|
2013-11-13 14:16:00 +04:00
|
|
|
QString err = _getFileRecordQuery->lastError().text();
|
2014-06-02 14:08:28 +04:00
|
|
|
qDebug() << "No journal entry found for " << filename;
|
2013-10-03 17:27:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rec;
|
|
|
|
}
|
|
|
|
|
2014-06-17 18:29:38 +04:00
|
|
|
bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
2013-11-11 14:11:45 +04:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-11-11 14:11:45 +04:00
|
|
|
return false;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-11-11 14:11:45 +04:00
|
|
|
|
2013-11-18 16:02:09 +04:00
|
|
|
QSqlQuery query(_db);
|
|
|
|
query.prepare("SELECT phash, path FROM metadata order by path");
|
2013-11-11 14:11:45 +04:00
|
|
|
|
|
|
|
if (!query.exec()) {
|
|
|
|
QString err = query.lastError().text();
|
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList superfluousItems;
|
|
|
|
|
|
|
|
while(query.next()) {
|
|
|
|
const QString file = query.value(1).toString();
|
|
|
|
bool contained = items.contains(file);
|
|
|
|
if( !contained ) {
|
|
|
|
superfluousItems.append(query.value(0).toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( superfluousItems.count() ) {
|
|
|
|
QString sql = "DELETE FROM metadata WHERE phash in ("+ superfluousItems.join(",")+")";
|
|
|
|
qDebug() << "Sync Journal cleanup: " << sql;
|
2013-11-18 16:02:09 +04:00
|
|
|
QSqlQuery delQuery(_db);
|
|
|
|
delQuery.prepare(sql);
|
2013-11-11 14:11:45 +04:00
|
|
|
if( !delQuery.exec() ) {
|
|
|
|
QString err = delQuery.lastError().text();
|
|
|
|
qDebug() << "Error removing superfluous journal entries: " << delQuery.lastQuery() << ", Error:" << err;;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-04 16:44:57 +04:00
|
|
|
int SyncJournalDb::getFileRecordCount()
|
|
|
|
{
|
2013-11-18 13:02:15 +04:00
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-11-18 13:02:15 +04:00
|
|
|
return -1;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-10-04 16:44:57 +04:00
|
|
|
|
2013-11-18 16:02:09 +04:00
|
|
|
QSqlQuery query(_db);
|
|
|
|
query.prepare("SELECT COUNT(*) FROM metadata");
|
2013-10-04 16:44:57 +04:00
|
|
|
|
|
|
|
if (!query.exec()) {
|
|
|
|
QString err = query.lastError().text();
|
|
|
|
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.next()) {
|
|
|
|
int count = query.value(0).toInt();
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-16 13:59:54 +04:00
|
|
|
SyncJournalDb::DownloadInfo SyncJournalDb::getDownloadInfo(const QString& file)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
DownloadInfo res;
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
2013-11-13 14:16:00 +04:00
|
|
|
_getDownloadInfoQuery->bindValue(":pa", file);
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if (!_getDownloadInfoQuery->exec()) {
|
|
|
|
QString err = _getDownloadInfoQuery->lastError().text();
|
|
|
|
qDebug() << "Database error for file " << file << " : " << _getDownloadInfoQuery->lastQuery() << ", Error:" << err;;
|
2013-10-16 13:59:54 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( _getDownloadInfoQuery->next() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
bool ok = true;
|
2013-11-13 14:16:00 +04:00
|
|
|
res._tmpfile = _getDownloadInfoQuery->value(0).toString();
|
|
|
|
res._etag = _getDownloadInfoQuery->value(1).toByteArray();
|
|
|
|
res._errorCount = _getDownloadInfoQuery->value(2).toInt(&ok);
|
2013-10-16 13:59:54 +04:00
|
|
|
res._valid = ok;
|
|
|
|
}
|
2013-11-13 14:16:00 +04:00
|
|
|
_getDownloadInfoQuery->finish();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setDownloadInfo(const QString& file, const SyncJournalDb::DownloadInfo& i)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-10-16 13:59:54 +04:00
|
|
|
|
|
|
|
if (i._valid) {
|
2013-11-13 14:16:00 +04:00
|
|
|
_setDownloadInfoQuery->bindValue(0, file);
|
|
|
|
_setDownloadInfoQuery->bindValue(1, i._tmpfile);
|
|
|
|
_setDownloadInfoQuery->bindValue(2, i._etag );
|
|
|
|
_setDownloadInfoQuery->bindValue(3, i._errorCount );
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( !_setDownloadInfoQuery->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: " << _setDownloadInfoQuery->lastQuery() << " :" << _setDownloadInfoQuery->lastError().text();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _setDownloadInfoQuery->lastQuery() << file << i._tmpfile << i._etag << i._errorCount;
|
|
|
|
_setDownloadInfoQuery->finish();
|
|
|
|
|
2013-10-16 13:59:54 +04:00
|
|
|
} else {
|
2013-11-13 14:16:00 +04:00
|
|
|
_deleteDownloadInfoQuery->bindValue( 0, file );
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( !_deleteDownloadInfoQuery->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: " << _deleteDownloadInfoQuery->lastQuery() << " : " << _deleteDownloadInfoQuery->lastError().text();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _deleteDownloadInfoQuery->executedQuery() << file;
|
|
|
|
_deleteDownloadInfoQuery->finish();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SyncJournalDb::UploadInfo SyncJournalDb::getUploadInfo(const QString& file)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
UploadInfo res;
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
_getUploadInfoQuery->bindValue(":pa", file);
|
|
|
|
|
|
|
|
if (!_getUploadInfoQuery->exec()) {
|
|
|
|
QString err = _getUploadInfoQuery->lastError().text();
|
|
|
|
qDebug() << "Database error for file " << file << " : " << _getUploadInfoQuery->lastQuery() << ", Error:" << err;
|
2013-10-16 13:59:54 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( _getUploadInfoQuery->next() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
bool ok = true;
|
2013-11-13 14:16:00 +04:00
|
|
|
res._chunk = _getUploadInfoQuery->value(0).toInt(&ok);
|
|
|
|
res._transferid = _getUploadInfoQuery->value(1).toInt(&ok);
|
|
|
|
res._errorCount = _getUploadInfoQuery->value(2).toInt(&ok);
|
|
|
|
res._size = _getUploadInfoQuery->value(3).toLongLong(&ok);
|
2014-01-29 14:39:14 +04:00
|
|
|
res._modtime = Utility::qDateTimeFromTime_t(_getUploadInfoQuery->value(4).toLongLong(&ok));
|
2013-10-16 13:59:54 +04:00
|
|
|
res._valid = ok;
|
|
|
|
}
|
2013-11-13 14:16:00 +04:00
|
|
|
_getUploadInfoQuery->finish();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setUploadInfo(const QString& file, const SyncJournalDb::UploadInfo& i)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-10-16 13:59:54 +04:00
|
|
|
|
|
|
|
if (i._valid) {
|
2013-11-13 14:16:00 +04:00
|
|
|
_setUploadInfoQuery->bindValue(0, file);
|
|
|
|
_setUploadInfoQuery->bindValue(1, i._chunk);
|
|
|
|
_setUploadInfoQuery->bindValue(2, i._transferid );
|
|
|
|
_setUploadInfoQuery->bindValue(3, i._errorCount );
|
|
|
|
_setUploadInfoQuery->bindValue(4, i._size );
|
2014-01-29 14:39:14 +04:00
|
|
|
_setUploadInfoQuery->bindValue(5, Utility::qDateTimeToTime_t(i._modtime) );
|
2013-11-13 14:16:00 +04:00
|
|
|
|
|
|
|
if( !_setUploadInfoQuery->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: " << _setUploadInfoQuery->lastQuery() << " :" << _setUploadInfoQuery->lastError().text();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _setUploadInfoQuery->lastQuery() << file << i._chunk << i._transferid << i._errorCount;
|
|
|
|
_setUploadInfoQuery->finish();
|
2013-10-16 13:59:54 +04:00
|
|
|
} else {
|
2013-11-13 14:16:00 +04:00
|
|
|
_deleteUploadInfoQuery->bindValue(0, file);
|
2013-10-16 13:59:54 +04:00
|
|
|
|
2013-11-13 14:16:00 +04:00
|
|
|
if( !_deleteUploadInfoQuery->exec() ) {
|
|
|
|
qWarning() << "Exec error of SQL statement: " << _deleteUploadInfoQuery->lastQuery() << " : " << _deleteUploadInfoQuery->lastError().text();
|
2013-10-16 13:59:54 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-11-13 14:16:00 +04:00
|
|
|
qDebug() << _deleteUploadInfoQuery->executedQuery() << file;
|
|
|
|
_deleteUploadInfoQuery->finish();
|
2013-10-16 13:59:54 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
SyncJournalBlacklistRecord SyncJournalDb::blacklistEntry( const QString& file )
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
SyncJournalBlacklistRecord entry;
|
|
|
|
|
|
|
|
if( file.isEmpty() ) return entry;
|
|
|
|
|
|
|
|
// SELECT lastTryEtag, lastTryModtime, retrycount, errorstring
|
|
|
|
|
|
|
|
if( checkConnect() ) {
|
|
|
|
_blacklistQuery->bindValue( ":path", file );
|
|
|
|
if( _blacklistQuery->exec() ){
|
|
|
|
if( _blacklistQuery->next() ) {
|
|
|
|
bool ok;
|
|
|
|
entry._lastTryEtag = _blacklistQuery->value(0).toByteArray();
|
|
|
|
entry._lastTryModtime = _blacklistQuery->value(1).toLongLong(&ok);
|
|
|
|
entry._retryCount = _blacklistQuery->value(2).toInt();
|
|
|
|
entry._errorString = _blacklistQuery->value(3).toString();
|
|
|
|
entry._file = file;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qWarning() << "Exec error blacklist: " << _blacklistQuery->lastQuery() << " : "
|
|
|
|
<< _blacklistQuery->lastError().text();
|
|
|
|
}
|
|
|
|
_blacklistQuery->finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2013-12-03 17:47:32 +04:00
|
|
|
int SyncJournalDb::blackListEntryCount()
|
|
|
|
{
|
|
|
|
int re = 0;
|
|
|
|
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( checkConnect() ) {
|
|
|
|
QSqlQuery query(_db);
|
2013-12-12 14:38:41 +04:00
|
|
|
if( ! query.exec("SELECT count(*) FROM blacklist") ) {
|
2013-12-03 17:47:32 +04:00
|
|
|
sqlFail("Count number of blacklist entries failed", query);
|
|
|
|
}
|
|
|
|
if( query.next() ) {
|
|
|
|
re = query.value(0).toInt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return re;
|
|
|
|
}
|
|
|
|
|
2013-12-03 17:03:45 +04:00
|
|
|
int SyncJournalDb::wipeBlacklist()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( checkConnect() ) {
|
|
|
|
QSqlQuery query(_db);
|
|
|
|
|
2013-12-12 14:38:41 +04:00
|
|
|
query.prepare("DELETE FROM blacklist");
|
2013-12-03 17:03:45 +04:00
|
|
|
|
|
|
|
if( ! query.exec() ) {
|
|
|
|
sqlFail("Deletion of whole blacklist failed", query);
|
2013-12-03 17:47:32 +04:00
|
|
|
return -1;
|
2013-12-03 17:03:45 +04:00
|
|
|
}
|
|
|
|
return query.numRowsAffected();
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
void SyncJournalDb::wipeBlacklistEntry( const QString& file )
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
2013-11-20 21:19:14 +04:00
|
|
|
if( checkConnect() ) {
|
2013-11-22 18:37:35 +04:00
|
|
|
QSqlQuery query(_db);
|
2013-11-20 16:44:01 +04:00
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
query.prepare("DELETE FROM blacklist WHERE path=:path");
|
|
|
|
query.bindValue(":path", file);
|
|
|
|
if( ! query.exec() ) {
|
2013-12-03 17:03:45 +04:00
|
|
|
sqlFail("Deletion of blacklist item failed.", query);
|
2013-11-20 21:19:14 +04:00
|
|
|
}
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::updateBlacklistEntry( const SyncJournalBlacklistRecord& item )
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
2013-11-22 18:37:35 +04:00
|
|
|
QSqlQuery query(_db);
|
2013-11-20 16:44:01 +04:00
|
|
|
|
2013-11-20 21:19:14 +04:00
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-23 18:00:51 +04:00
|
|
|
QString sql("SELECT retrycount FROM blacklist WHERE path=:path");
|
|
|
|
|
|
|
|
if( Utility::fsCasePreserving() ) {
|
|
|
|
// if the file system is case preserving we have to check the blacklist
|
|
|
|
// case insensitively
|
|
|
|
sql += QLatin1String(" COLLATE NOCASE");
|
|
|
|
}
|
|
|
|
|
|
|
|
query.prepare(sql);
|
2013-11-20 16:44:01 +04:00
|
|
|
query.bindValue(":path", item._file);
|
|
|
|
|
|
|
|
if( !query.exec() ) {
|
2013-11-20 21:19:14 +04:00
|
|
|
qDebug() << "SQL exec blacklistitem failed:" << query.lastError().text();
|
2013-11-20 16:44:01 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-22 18:37:35 +04:00
|
|
|
QSqlQuery iQuery(_db);
|
2013-11-20 16:44:01 +04:00
|
|
|
if( query.next() ) {
|
|
|
|
int retries = query.value(0).toInt();
|
|
|
|
retries--;
|
|
|
|
if( retries < 0 ) retries = 0;
|
|
|
|
|
|
|
|
iQuery.prepare( "UPDATE blacklist SET lastTryEtag = :etag, lastTryModtime = :modtime, "
|
|
|
|
"retrycount = :retries, errorstring = :errStr WHERE path=:path");
|
|
|
|
iQuery.bindValue(":etag", item._lastTryEtag);
|
|
|
|
iQuery.bindValue(":modtime", QString::number(item._lastTryModtime));
|
|
|
|
iQuery.bindValue(":retries", retries);
|
|
|
|
iQuery.bindValue(":errStr", item._errorString);
|
|
|
|
iQuery.bindValue(":path", item._file);
|
|
|
|
} else {
|
|
|
|
// there is no entry yet.
|
|
|
|
iQuery.prepare("INSERT INTO blacklist (path, lastTryEtag, lastTryModtime, retrycount, errorstring) "
|
|
|
|
"VALUES (:path, :lastEtag, :lastMTime, :retrycount, :errorstring);");
|
|
|
|
|
|
|
|
iQuery.bindValue(":path", item._file );
|
|
|
|
iQuery.bindValue(":lastEtag", item._lastTryEtag);
|
|
|
|
iQuery.bindValue(":lastMTime", QString::number(item._lastTryModtime));
|
|
|
|
iQuery.bindValue(":retrycount", item._retryCount);
|
|
|
|
iQuery.bindValue(":errorstring", item._errorString);
|
|
|
|
}
|
|
|
|
if( !iQuery.exec() ) {
|
|
|
|
qDebug() << "SQL exec blacklistitem insert/update failed: "<< iQuery.lastError().text();
|
|
|
|
}
|
2013-11-25 18:11:37 +04:00
|
|
|
|
2013-11-20 16:44:01 +04:00
|
|
|
}
|
|
|
|
|
2014-07-28 14:12:52 +04:00
|
|
|
QVector< SyncJournalDb::PollInfo > SyncJournalDb::getPollInfos()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
QVector< SyncJournalDb::PollInfo > res;
|
|
|
|
|
2014-07-29 21:51:26 +04:00
|
|
|
if( !checkConnect() )
|
2014-07-28 14:12:52 +04:00
|
|
|
return res;
|
|
|
|
|
2014-07-29 21:51:26 +04:00
|
|
|
QSqlQuery query("SELECT path, modtime, pollpath FROM poll",_db);
|
2014-07-28 14:12:52 +04:00
|
|
|
|
|
|
|
if (!query.exec()) {
|
|
|
|
QString err = query.lastError().text();
|
|
|
|
qDebug() << "Database error :" << query.lastQuery() << ", Error:" << err;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( query.next() ) {
|
|
|
|
PollInfo info;
|
|
|
|
info._file = query.value(0).toString();
|
|
|
|
info._modtime = query.value(1).toLongLong();
|
|
|
|
info._url = query.value(2).toString();
|
|
|
|
res.append(info);
|
2014-07-29 21:51:26 +04:00
|
|
|
qDebug() << "§§§§§§§§§§§§§§§§" << info._file << info._url;
|
2014-07-28 14:12:52 +04:00
|
|
|
}
|
2014-07-29 21:51:26 +04:00
|
|
|
|
|
|
|
qDebug() << "§§§§§§§§§-*-*-*§§§§§§§" << res.count();
|
|
|
|
|
2014-07-28 14:12:52 +04:00
|
|
|
query.finish();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SyncJournalDb::setPollInfo(const SyncJournalDb::PollInfo& info)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-29 21:51:26 +04:00
|
|
|
if (info._url.isEmpty()) {
|
2014-07-28 14:12:52 +04:00
|
|
|
QSqlQuery query("DELETE FROM poll WHERE path=?", _db);
|
|
|
|
query.bindValue(0, info._file);
|
|
|
|
if( !query.exec() ) {
|
|
|
|
qDebug() << "SQL error in setPollInfo: "<< query.lastError().text();
|
|
|
|
} else {
|
|
|
|
qDebug() << query.executedQuery() << info._file;
|
|
|
|
}
|
|
|
|
} else {
|
2014-07-29 21:51:26 +04:00
|
|
|
QSqlQuery query("INSERT OR REPLACE INTO poll (path, modtime, pollpath) VALUES( ? , ? , ? )", _db);
|
2014-07-28 14:12:52 +04:00
|
|
|
query.bindValue(0, info._file);
|
|
|
|
query.bindValue(1, QString::number(info._modtime));
|
|
|
|
query.bindValue(2, info._url);
|
|
|
|
if( !query.exec() ) {
|
|
|
|
qDebug() << "SQL error in setPollInfo: "<< query.lastError().text();
|
|
|
|
} else {
|
|
|
|
qDebug() << query.executedQuery() << info._file << info._url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-12 16:44:55 +04:00
|
|
|
void SyncJournalDb::avoidRenamesOnNextSync(const QString& path)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSqlQuery query(_db);
|
2014-02-19 18:23:36 +04:00
|
|
|
query.prepare("UPDATE metadata SET fileid = '', inode = '0' WHERE path == ? OR path LIKE(?||'/%')");
|
2014-02-12 16:44:55 +04:00
|
|
|
query.bindValue(0, path);
|
2014-02-19 18:23:36 +04:00
|
|
|
query.bindValue(1, path);
|
2014-02-12 16:44:55 +04:00
|
|
|
if( !query.exec() ) {
|
2014-08-07 12:14:14 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
|
2014-02-12 16:44:55 +04:00
|
|
|
} else {
|
2014-08-07 12:14:14 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << query.executedQuery() << path << "(" << query.numRowsAffected() << " rows)";
|
2014-02-12 16:44:55 +04:00
|
|
|
}
|
2014-08-07 12:14:14 +04:00
|
|
|
|
|
|
|
// We also need to remove the ETags so the update phase refreshes the directory paths
|
|
|
|
// on the next sync
|
|
|
|
locker.unlock();
|
|
|
|
avoidReadFromDbOnNextSync(path);
|
2014-02-12 16:44:55 +04:00
|
|
|
}
|
|
|
|
|
2014-06-03 19:22:40 +04:00
|
|
|
void SyncJournalDb::avoidReadFromDbOnNextSync(const QString& fileName)
|
|
|
|
{
|
|
|
|
//Make sure that on the next sync, filName is not read from the DB but use the PROPFIND to
|
|
|
|
//get the info from the server
|
|
|
|
// We achieve that by clearing the etag of the parents directory recursively
|
|
|
|
|
|
|
|
QMutexLocker locker(&_mutex);
|
|
|
|
|
|
|
|
if( !checkConnect() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSqlQuery query(_db);
|
|
|
|
// This query will match entries for whitch the path is a prefix of fileName
|
|
|
|
query.prepare("UPDATE metadata SET md5='_invalid_' WHERE ? LIKE(path||'/%') AND type == 2"); // CSYNC_FTW_TYPE_DIR == 2
|
|
|
|
query.bindValue(0, fileName);
|
|
|
|
if( !query.exec() ) {
|
2014-08-07 12:14:14 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << "SQL error in avoidRenamesOnNextSync: "<< query.lastError().text();
|
2014-06-03 19:22:40 +04:00
|
|
|
} else {
|
2014-08-07 12:14:14 +04:00
|
|
|
qDebug() << Q_FUNC_INFO << query.executedQuery() << fileName << "(" << query.numRowsAffected() << " rows)";
|
2014-06-03 19:22:40 +04:00
|
|
|
}
|
2014-08-07 14:10:32 +04:00
|
|
|
|
|
|
|
// Prevent future overwrite of the etag for this sync
|
|
|
|
_avoidReadFromDbOnNextSyncFilter.append(fileName);
|
2014-06-03 19:22:40 +04:00
|
|
|
}
|
2014-02-12 16:44:55 +04:00
|
|
|
|
2013-11-25 18:11:37 +04:00
|
|
|
void SyncJournalDb::commit(const QString& context, bool startTrans)
|
|
|
|
{
|
|
|
|
QMutexLocker lock(&_mutex);
|
|
|
|
commitInternal(context, startTrans);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SyncJournalDb::commitInternal(const QString& context, bool startTrans )
|
2013-11-18 12:59:59 +04:00
|
|
|
{
|
2013-11-21 14:13:58 +04:00
|
|
|
qDebug() << "Transaction Start " << context;
|
|
|
|
commitTransaction();
|
|
|
|
|
|
|
|
if( startTrans ) {
|
|
|
|
startTransaction();
|
2013-11-18 12:59:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SyncJournalDb::~SyncJournalDb()
|
|
|
|
{
|
2013-11-25 18:07:58 +04:00
|
|
|
close();
|
2013-11-18 12:59:59 +04:00
|
|
|
}
|
|
|
|
|
2014-04-01 15:41:47 +04:00
|
|
|
bool SyncJournalDb::isConnected()
|
|
|
|
{
|
|
|
|
QMutexLocker lock(&_mutex);
|
|
|
|
return checkConnect();
|
|
|
|
}
|
|
|
|
|
2014-04-25 15:31:44 +04:00
|
|
|
bool SyncJournalDb::isUpdateFrom_1_5()
|
|
|
|
{
|
|
|
|
QMutexLocker lock(&_mutex);
|
|
|
|
checkConnect();
|
|
|
|
return _possibleUpgradeFromMirall_1_5;
|
|
|
|
}
|
|
|
|
|
2014-04-01 15:41:47 +04:00
|
|
|
|
2013-10-03 17:27:29 +04:00
|
|
|
|
|
|
|
} // namespace Mirall
|