2008-02-27 20:56:47 +03:00
|
|
|
/*
|
|
|
|
* libcsync -- a library to sync a directory with another
|
|
|
|
*
|
2013-07-23 19:31:55 +04:00
|
|
|
* Copyright (c) 2008-2013 by Andreas Schneider <asn@cryptomilk.org>
|
2013-12-11 17:54:34 +04:00
|
|
|
* Copyright (c) 2012-2013 by Klaas Freitag <freitag@owncloud.com>
|
2008-02-27 20:56:47 +03:00
|
|
|
*
|
2013-07-23 19:31:55 +04:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2008-02-27 20:56:47 +03:00
|
|
|
*
|
2013-07-23 19:31:55 +04:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
2008-02-27 20:56:47 +03:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2013-07-23 19:31:55 +04:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2008-02-27 20:56:47 +03:00
|
|
|
*
|
2013-07-23 19:31:55 +04:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2008-02-27 20:56:47 +03:00
|
|
|
*/
|
|
|
|
|
2014-01-15 15:20:03 +04:00
|
|
|
#include "config_csync.h"
|
2012-03-02 19:47:34 +04:00
|
|
|
|
2008-06-09 19:19:12 +04:00
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
2008-02-27 20:56:47 +03:00
|
|
|
#include <sqlite3.h>
|
2008-02-29 13:24:14 +03:00
|
|
|
#include <stdio.h>
|
2008-02-27 20:56:47 +03:00
|
|
|
#include <unistd.h>
|
2008-03-20 12:45:05 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2013-08-15 15:35:24 +04:00
|
|
|
#include <errno.h>
|
2008-02-27 20:56:47 +03:00
|
|
|
|
2008-03-04 12:42:02 +03:00
|
|
|
#include "c_lib.h"
|
2008-02-27 20:56:47 +03:00
|
|
|
#include "csync_private.h"
|
2008-07-09 11:57:19 +04:00
|
|
|
#include "csync_statedb.h"
|
2008-06-28 19:18:10 +04:00
|
|
|
#include "csync_util.h"
|
2012-10-04 15:02:38 +04:00
|
|
|
#include "csync_misc.h"
|
2008-02-27 20:56:47 +03:00
|
|
|
|
2012-10-31 22:26:48 +04:00
|
|
|
#include "c_string.h"
|
2013-07-08 15:37:11 +04:00
|
|
|
#include "c_jhash.h"
|
2013-05-20 14:24:01 +04:00
|
|
|
#include "csync_time.h"
|
2012-10-31 22:26:48 +04:00
|
|
|
|
2008-07-09 12:10:00 +04:00
|
|
|
#define CSYNC_LOG_CATEGORY_NAME "csync.statedb"
|
2008-02-27 20:56:47 +03:00
|
|
|
#include "csync_log.h"
|
2013-07-08 15:37:11 +04:00
|
|
|
#include "csync_rename.h"
|
2008-02-27 20:56:47 +03:00
|
|
|
|
2008-05-06 16:31:36 +04:00
|
|
|
#define BUF_SIZE 16
|
|
|
|
|
2008-07-09 12:10:00 +04:00
|
|
|
void csync_set_statedb_exists(CSYNC *ctx, int val) {
|
|
|
|
ctx->statedb.exists = val;
|
2008-06-24 13:13:17 +04:00
|
|
|
}
|
|
|
|
|
2008-07-09 12:10:00 +04:00
|
|
|
int csync_get_statedb_exists(CSYNC *ctx) {
|
|
|
|
return ctx->statedb.exists;
|
2008-06-24 13:13:17 +04:00
|
|
|
}
|
|
|
|
|
2012-11-01 00:08:40 +04:00
|
|
|
/* Set the hide attribute in win32. That makes it invisible in normal explorers */
|
2012-10-31 22:26:48 +04:00
|
|
|
static void _csync_win32_hide_file( const char *file ) {
|
|
|
|
#ifdef _WIN32
|
2013-08-18 18:43:46 +04:00
|
|
|
mbchar_t *fileName;
|
2013-07-31 15:12:10 +04:00
|
|
|
DWORD dwAttrs;
|
|
|
|
|
2012-10-31 22:26:48 +04:00
|
|
|
if( !file ) return;
|
|
|
|
|
2013-08-18 18:43:46 +04:00
|
|
|
fileName = c_utf8_to_locale( file );
|
2013-07-31 15:12:10 +04:00
|
|
|
dwAttrs = GetFileAttributesW(fileName);
|
2012-10-31 22:26:48 +04:00
|
|
|
|
|
|
|
if (dwAttrs==INVALID_FILE_ATTRIBUTES) return;
|
|
|
|
|
|
|
|
if (!(dwAttrs & FILE_ATTRIBUTE_HIDDEN)) {
|
|
|
|
SetFileAttributesW(fileName, dwAttrs | FILE_ATTRIBUTE_HIDDEN );
|
|
|
|
}
|
|
|
|
|
2013-08-18 18:43:46 +04:00
|
|
|
c_free_locale_string(fileName);
|
2012-11-01 00:08:40 +04:00
|
|
|
#else
|
|
|
|
(void) file;
|
2012-10-31 22:26:48 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-07-04 12:28:19 +04:00
|
|
|
static int _csync_check_db_integrity(sqlite3 *db) {
|
2013-05-21 17:33:09 +04:00
|
|
|
c_strlist_t *result = NULL;
|
|
|
|
int rc = -1;
|
|
|
|
|
2013-07-04 12:28:19 +04:00
|
|
|
result = csync_statedb_query(db, "PRAGMA quick_check;");
|
2013-05-21 17:33:09 +04:00
|
|
|
if (result != NULL) {
|
|
|
|
/* There is a result */
|
|
|
|
if (result->count > 0) {
|
|
|
|
if (c_streq(result->vector[0], "ok")) {
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c_strlist_destroy(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-07-04 12:28:19 +04:00
|
|
|
static int _csync_statedb_check(const char *statedb) {
|
2012-10-29 13:40:43 +04:00
|
|
|
int fd = -1, rc;
|
2012-10-19 22:14:23 +04:00
|
|
|
ssize_t r;
|
2008-05-06 16:31:36 +04:00
|
|
|
char buf[BUF_SIZE] = {0};
|
2008-02-27 20:56:47 +03:00
|
|
|
sqlite3 *db = NULL;
|
2013-09-10 14:59:29 +04:00
|
|
|
csync_stat_t sb;
|
2013-05-21 17:33:09 +04:00
|
|
|
|
2013-06-05 19:59:34 +04:00
|
|
|
mbchar_t *wstatedb = c_utf8_to_locale(statedb);
|
|
|
|
|
|
|
|
if (wstatedb == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2008-02-27 20:56:47 +03:00
|
|
|
|
|
|
|
/* check db version */
|
2012-03-07 17:46:47 +04:00
|
|
|
#ifdef _WIN32
|
2013-05-21 17:33:09 +04:00
|
|
|
_fmode = _O_BINARY;
|
2012-03-07 17:46:47 +04:00
|
|
|
#endif
|
2012-11-27 18:39:06 +04:00
|
|
|
|
2013-05-21 17:33:09 +04:00
|
|
|
fd = _topen(wstatedb, O_RDONLY);
|
|
|
|
|
|
|
|
if (fd >= 0) {
|
2013-07-09 19:30:40 +04:00
|
|
|
/* Check size. Size of zero is a valid database actually. */
|
2013-07-31 15:12:10 +04:00
|
|
|
rc = _tfstat(fd, &sb);
|
2013-07-09 19:30:40 +04:00
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
if (sb.st_size == 0) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Database size is zero byte!");
|
2013-08-16 14:20:05 +04:00
|
|
|
close(fd);
|
2013-07-09 19:30:40 +04:00
|
|
|
} else {
|
|
|
|
r = read(fd, (void *) buf, sizeof(buf) - 1);
|
|
|
|
close(fd);
|
|
|
|
if (r >= 0) {
|
|
|
|
buf[BUF_SIZE - 1] = '\0';
|
|
|
|
if (c_streq(buf, "SQLite format 3")) {
|
2013-08-18 18:21:18 +04:00
|
|
|
if (sqlite3_open(statedb, &db ) == SQLITE_OK) {
|
|
|
|
rc = _csync_check_db_integrity(db);
|
|
|
|
if( sqlite3_close(db) != 0 ) {
|
2013-08-15 20:37:30 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "WARN: sqlite3_close error!");
|
|
|
|
}
|
2013-07-09 19:30:40 +04:00
|
|
|
|
|
|
|
if( rc >= 0 ) {
|
|
|
|
/* everything is fine */
|
2013-08-18 18:21:18 +04:00
|
|
|
c_free_locale_string(wstatedb);
|
2013-07-09 19:30:40 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Integrity check failed!");
|
|
|
|
} else {
|
2013-08-18 18:21:18 +04:00
|
|
|
/* resources need to be freed even when open failed */
|
|
|
|
sqlite3_close(db);
|
2013-07-09 19:30:40 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "database corrupted, removing!");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "sqlite version mismatch");
|
2013-05-21 17:33:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
2013-07-09 19:30:40 +04:00
|
|
|
/* if it comes here, the database is broken and should be recreated. */
|
2013-05-21 17:33:09 +04:00
|
|
|
_tunlink(wstatedb);
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
|
|
|
|
2013-06-05 19:59:34 +04:00
|
|
|
c_free_locale_string(wstatedb);
|
2008-02-27 20:56:47 +03:00
|
|
|
|
|
|
|
/* create database */
|
2012-10-29 13:40:43 +04:00
|
|
|
rc = sqlite3_open(statedb, &db);
|
|
|
|
if (rc == SQLITE_OK) {
|
2008-02-27 20:56:47 +03:00
|
|
|
sqlite3_close(db);
|
2013-08-18 22:13:27 +04:00
|
|
|
_csync_win32_hide_file(statedb);
|
|
|
|
return 1;
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
2008-04-30 14:32:35 +04:00
|
|
|
sqlite3_close(db);
|
2013-08-18 22:13:27 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_open failed: %s %s", sqlite3_errmsg(db), statedb);
|
|
|
|
return -1;
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
|
|
|
|
2013-07-04 12:28:19 +04:00
|
|
|
static int _csync_statedb_is_empty(sqlite3 *db) {
|
2008-02-27 20:56:47 +03:00
|
|
|
c_strlist_t *result = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
|
2013-07-04 12:28:19 +04:00
|
|
|
result = csync_statedb_query(db, "SELECT COUNT(phash) FROM metadata LIMIT 1 OFFSET 0;");
|
2008-04-29 13:41:16 +04:00
|
|
|
if (result == NULL) {
|
2008-02-27 20:56:47 +03:00
|
|
|
rc = 1;
|
|
|
|
}
|
|
|
|
c_strlist_destroy(result);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
#ifndef NDEBUG
|
|
|
|
static void sqlite_profile( void *x, const char* sql, sqlite3_uint64 time)
|
|
|
|
{
|
|
|
|
(void)x;
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
|
|
|
|
"_SQL_ %s: %llu", sql, time);
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-06-26 01:14:08 +04:00
|
|
|
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb) {
|
2008-02-29 13:24:14 +03:00
|
|
|
int rc = -1;
|
2013-05-22 18:10:28 +04:00
|
|
|
int check_rc = -1;
|
2008-04-29 16:19:50 +04:00
|
|
|
c_strlist_t *result = NULL;
|
2013-07-04 14:24:40 +04:00
|
|
|
sqlite3 *db = NULL;
|
2008-02-29 13:24:14 +03:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( !ctx ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-10-04 15:02:38 +04:00
|
|
|
/* csync_statedb_check tries to open the statedb and creates it in case
|
|
|
|
* its not there.
|
|
|
|
*/
|
2013-08-18 18:21:18 +04:00
|
|
|
check_rc = _csync_statedb_check(statedb);
|
2013-05-22 18:10:28 +04:00
|
|
|
if (check_rc < 0) {
|
2013-04-15 19:47:50 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: checking csync database failed - bail out.");
|
|
|
|
|
2008-02-29 13:24:14 +03:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-04-15 19:47:50 +04:00
|
|
|
/* Open or create the temporary database */
|
2014-03-26 13:20:30 +04:00
|
|
|
if (sqlite3_open(statedb, &db) != SQLITE_OK) {
|
2013-04-15 19:47:50 +04:00
|
|
|
const char *errmsg= sqlite3_errmsg(ctx->statedb.db);
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "ERR: Failed to sqlite3 open statedb - bail out: %s.",
|
|
|
|
errmsg ? errmsg : "<no sqlite3 errormsg>");
|
|
|
|
|
2008-02-29 13:24:14 +03:00
|
|
|
rc = -1;
|
|
|
|
goto out;
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
|
|
|
|
2013-05-22 18:10:28 +04:00
|
|
|
/* If check_rc == 1 the database is new and empty as a result. */
|
2013-08-18 18:21:18 +04:00
|
|
|
if ((check_rc == 1) || _csync_statedb_is_empty(db)) {
|
2008-07-09 12:10:00 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_NOTICE, "statedb doesn't exist");
|
|
|
|
csync_set_statedb_exists(ctx, 0);
|
2008-02-27 20:56:47 +03:00
|
|
|
} else {
|
2008-07-09 12:10:00 +04:00
|
|
|
csync_set_statedb_exists(ctx, 1);
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
|
|
|
|
2008-04-29 16:19:50 +04:00
|
|
|
/* optimization for speeding up SQLite */
|
2013-08-18 18:21:18 +04:00
|
|
|
result = csync_statedb_query(db, "PRAGMA synchronous = FULL;");
|
2008-04-29 16:19:50 +04:00
|
|
|
c_strlist_destroy(result);
|
2013-08-18 18:21:18 +04:00
|
|
|
result = csync_statedb_query(db, "PRAGMA case_sensitive_like = ON;");
|
2012-10-27 14:03:39 +04:00
|
|
|
c_strlist_destroy(result);
|
2008-04-29 16:19:50 +04:00
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
#ifndef NDEBUG
|
|
|
|
sqlite3_profile(db, sqlite_profile, 0 );
|
|
|
|
#endif
|
2013-06-26 01:14:08 +04:00
|
|
|
*pdb = db;
|
|
|
|
|
|
|
|
return 0;
|
2008-02-29 13:24:14 +03:00
|
|
|
out:
|
2013-06-26 01:14:08 +04:00
|
|
|
sqlite3_close(db);
|
2008-04-29 16:19:50 +04:00
|
|
|
return rc;
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
|
|
|
|
2014-03-26 13:20:30 +04:00
|
|
|
int csync_statedb_close(CSYNC *ctx) {
|
2008-04-29 13:21:43 +04:00
|
|
|
int rc = 0;
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if (!ctx) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-12 18:37:33 +04:00
|
|
|
/* deallocate query resources */
|
2014-03-19 19:22:25 +04:00
|
|
|
if( ctx->statedb.by_hash_stmt ) {
|
|
|
|
rc = sqlite3_finalize(ctx->statedb.by_hash_stmt);
|
|
|
|
ctx->statedb.by_hash_stmt = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ctx->statedb.by_fileid_stmt ) {
|
|
|
|
rc = sqlite3_finalize(ctx->statedb.by_fileid_stmt);
|
|
|
|
ctx->statedb.by_fileid_stmt = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ctx->statedb.by_inode_stmt ) {
|
|
|
|
rc = sqlite3_finalize(ctx->statedb.by_inode_stmt);
|
|
|
|
ctx->statedb.by_inode_stmt = NULL;
|
|
|
|
}
|
2013-07-12 18:37:33 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
sqlite3_close(ctx->statedb.db);
|
2013-07-12 18:37:33 +04:00
|
|
|
|
2008-04-29 13:21:43 +04:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
// This funciton parses a line from the metadata table into the given csync_file_stat
|
|
|
|
// structure which it is also allocating.
|
|
|
|
// Note that this function calls laso sqlite3_step to actually get the info from db and
|
|
|
|
// returns the sqlite return type.
|
|
|
|
static int _csync_file_stat_from_metadata_table( csync_file_stat_t **st, sqlite3_stmt *stmt )
|
|
|
|
{
|
|
|
|
int rc = SQLITE_ERROR;
|
|
|
|
int column_count;
|
|
|
|
int len;
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( ! stmt ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Fatal: Statement is NULL.");
|
|
|
|
return SQLITE_ERROR;
|
|
|
|
}
|
2014-02-07 14:52:37 +04:00
|
|
|
|
|
|
|
column_count = sqlite3_column_count(stmt);
|
|
|
|
|
|
|
|
rc = sqlite3_step(stmt);
|
|
|
|
|
|
|
|
if( rc == SQLITE_ROW ) {
|
|
|
|
if(column_count > 7) {
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
/* phash, pathlen, path, inode, uid, gid, mode, modtime */
|
|
|
|
len = sqlite3_column_int(stmt, 1);
|
|
|
|
*st = c_malloc(sizeof(csync_file_stat_t) + len + 1);
|
|
|
|
if (*st == NULL) {
|
2014-03-19 19:22:25 +04:00
|
|
|
return SQLITE_NOMEM;
|
2014-02-07 14:52:37 +04:00
|
|
|
}
|
|
|
|
/* clear the whole structure */
|
|
|
|
ZERO_STRUCTP(*st);
|
|
|
|
|
|
|
|
/* The query suceeded so use the phash we pass to the function. */
|
|
|
|
(*st)->phash = sqlite3_column_int64(stmt, 0);
|
|
|
|
|
|
|
|
(*st)->pathlen = sqlite3_column_int(stmt, 1);
|
|
|
|
name = (const char*) sqlite3_column_text(stmt, 2);
|
|
|
|
memcpy((*st)->path, (len ? name : ""), len + 1);
|
|
|
|
(*st)->inode = sqlite3_column_int64(stmt,3);
|
|
|
|
(*st)->uid = sqlite3_column_int(stmt, 4);
|
|
|
|
(*st)->gid = sqlite3_column_int(stmt, 5);
|
|
|
|
(*st)->mode = sqlite3_column_int(stmt, 6);
|
|
|
|
(*st)->modtime = strtoul((char*)sqlite3_column_text(stmt, 7), NULL, 10);
|
|
|
|
|
|
|
|
if(*st && column_count > 8 ) {
|
|
|
|
(*st)->type = sqlite3_column_int(stmt, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(column_count > 9 && sqlite3_column_text(stmt, 9)) {
|
|
|
|
(*st)->etag = c_strdup( (char*) sqlite3_column_text(stmt, 9) );
|
|
|
|
}
|
|
|
|
if(column_count > 10 && sqlite3_column_text(stmt,10)) {
|
|
|
|
csync_vio_set_file_id((*st)->file_id, (char*) sqlite3_column_text(stmt, 10));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-05-09 13:25:21 +04:00
|
|
|
/* caller must free the memory */
|
2014-03-19 19:22:25 +04:00
|
|
|
csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
|
2013-06-26 01:14:08 +04:00
|
|
|
uint64_t phash)
|
|
|
|
{
|
2008-04-30 18:23:42 +04:00
|
|
|
csync_file_stat_t *st = NULL;
|
2013-07-12 18:22:58 +04:00
|
|
|
int rc;
|
2008-04-30 18:23:42 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( !ctx ) {
|
2013-07-12 18:22:58 +04:00
|
|
|
return NULL;
|
2008-04-30 18:23:42 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( ctx->statedb.by_hash_stmt == NULL ) {
|
|
|
|
const char *hash_query = "SELECT * FROM metadata WHERE phash=?1";
|
|
|
|
|
|
|
|
rc = sqlite3_prepare_v2(ctx->statedb.db, hash_query, strlen(hash_query), &ctx->statedb.by_hash_stmt, NULL);
|
|
|
|
if( rc != SQLITE_OK ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ctx->statedb.by_hash_stmt == NULL ) {
|
2008-04-30 18:23:42 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
sqlite3_bind_int64(ctx->statedb.by_hash_stmt, 1, (long long signed int)phash);
|
2008-09-03 11:46:19 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_hash_stmt) < 0 ) {
|
2014-02-07 14:52:37 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata!");
|
2012-08-28 15:09:54 +04:00
|
|
|
}
|
2014-03-19 19:22:25 +04:00
|
|
|
sqlite3_reset(ctx->statedb.by_hash_stmt);
|
2008-04-30 18:23:42 +04:00
|
|
|
|
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
|
|
|
|
const char *file_id ) {
|
|
|
|
csync_file_stat_t *st = NULL;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!file_id) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (c_streq(file_id, "")) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !ctx ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ctx->statedb.by_fileid_stmt == NULL ) {
|
2014-03-20 00:00:59 +04:00
|
|
|
const char *query = "SELECT * FROM metadata WHERE fileid=?1";
|
2014-03-19 19:22:25 +04:00
|
|
|
|
|
|
|
rc = sqlite3_prepare_v2(ctx->statedb.db, query, strlen(query), &ctx->statedb.by_fileid_stmt, NULL);
|
|
|
|
if( rc != SQLITE_OK ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for file id query.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bind the query value */
|
|
|
|
sqlite3_bind_text(ctx->statedb.by_fileid_stmt, 1, file_id, -1, SQLITE_STATIC);
|
|
|
|
|
|
|
|
if( _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_fileid_stmt) < 0 ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata!");
|
|
|
|
}
|
|
|
|
// clear the resources used by the statement.
|
|
|
|
sqlite3_reset(ctx->statedb.by_fileid_stmt);
|
2013-10-25 15:14:25 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
return st;
|
|
|
|
}
|
2013-10-25 15:14:25 +04:00
|
|
|
|
2008-05-09 13:25:21 +04:00
|
|
|
/* caller must free the memory */
|
2014-03-19 19:22:25 +04:00
|
|
|
csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
|
|
|
|
uint64_t inode)
|
|
|
|
{
|
2008-04-30 18:23:42 +04:00
|
|
|
csync_file_stat_t *st = NULL;
|
2014-03-19 19:22:25 +04:00
|
|
|
int rc;
|
2008-04-30 18:23:42 +04:00
|
|
|
|
2013-12-03 15:51:18 +04:00
|
|
|
if (!inode) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( !ctx ) {
|
|
|
|
return NULL;
|
2008-04-30 18:23:42 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( ctx->statedb.by_inode_stmt == NULL ) {
|
|
|
|
const char *inode_query = "SELECT * FROM metadata WHERE inode=?1";
|
2008-04-30 18:23:42 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
rc = sqlite3_prepare_v2(ctx->statedb.db, inode_query, strlen(inode_query), &ctx->statedb.by_inode_stmt, NULL);
|
|
|
|
if( rc != SQLITE_OK ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for inode query.");
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-04-30 18:23:42 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( ctx->statedb.by_inode_stmt == NULL ) {
|
2008-04-30 18:23:42 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
sqlite3_bind_int64(ctx->statedb.by_inode_stmt, 1, (long long signed int)inode);
|
|
|
|
|
|
|
|
if( _csync_file_stat_from_metadata_table(&st, ctx->statedb.by_inode_stmt) < 0 ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Could not get line from metadata by inode!");
|
|
|
|
}
|
|
|
|
sqlite3_reset(ctx->statedb.by_inode_stmt);
|
2008-04-30 18:23:42 +04:00
|
|
|
|
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
/* Get the etag. */
|
|
|
|
char *csync_statedb_get_etag( CSYNC *ctx, uint64_t jHash ) {
|
2012-07-31 12:40:46 +04:00
|
|
|
char *ret = NULL;
|
2014-03-19 19:22:25 +04:00
|
|
|
csync_file_stat_t *fs = NULL;
|
2012-07-31 12:40:46 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( !ctx ) {
|
|
|
|
return NULL;
|
2012-07-31 12:40:46 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( ! csync_get_statedb_exists(ctx)) return ret;
|
2012-07-31 12:40:46 +04:00
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
fs = csync_statedb_get_stat_by_hash(ctx, jHash );
|
|
|
|
if( fs ) {
|
|
|
|
if( fs->etag ) {
|
|
|
|
ret = c_strdup(fs->etag);
|
|
|
|
}
|
|
|
|
csync_file_stat_free(fs);
|
|
|
|
}
|
2012-07-31 12:40:46 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
#define BELOW_PATH_QUERY "SELECT phash, pathlen, path, inode, uid, gid, mode, modtime, type, md5, fileid FROM metadata WHERE path LIKE(?)"
|
|
|
|
|
|
|
|
int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
|
|
|
int rc;
|
|
|
|
sqlite3_stmt *stmt = NULL;
|
|
|
|
int64_t cnt = 0;
|
|
|
|
char *likepath;
|
|
|
|
int asp;
|
|
|
|
|
|
|
|
if( !path ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-03-19 19:22:25 +04:00
|
|
|
if( !ctx ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
rc = sqlite3_prepare_v2(ctx->statedb.db, BELOW_PATH_QUERY, -1, &stmt, NULL);
|
|
|
|
if( rc != SQLITE_OK ) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "WRN: Unable to create stmt for hash query.");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-10-16 15:14:04 +04:00
|
|
|
|
|
|
|
if (stmt == NULL) {
|
2014-02-07 14:52:37 +04:00
|
|
|
return -1;
|
2012-10-16 15:14:04 +04:00
|
|
|
}
|
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
asp = asprintf( &likepath, "%s/%%%%", path);
|
|
|
|
if (asp < 0) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "asprintf failed!");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-10-16 15:14:04 +04:00
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
sqlite3_bind_text(stmt, 1, likepath, -1, SQLITE_STATIC);
|
2012-10-16 15:14:04 +04:00
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
cnt = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
csync_file_stat_t *st = NULL;
|
|
|
|
|
|
|
|
rc = _csync_file_stat_from_metadata_table( &st, stmt);
|
|
|
|
if( st ) {
|
|
|
|
/* store into result list. */
|
|
|
|
if (c_rbtree_insert(ctx->remote.tree, (void *) st) < 0) {
|
|
|
|
SAFE_FREE(st);
|
|
|
|
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
} while( rc == SQLITE_ROW );
|
|
|
|
|
|
|
|
if( rc != SQLITE_DONE ) {
|
|
|
|
ctx->status_code = CSYNC_STATUS_TREE_ERROR;
|
|
|
|
} else {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "%ld entries read below path %s from db.", cnt, path);
|
|
|
|
}
|
|
|
|
sqlite3_finalize(stmt);
|
|
|
|
SAFE_FREE(likepath);
|
2012-10-16 15:14:04 +04:00
|
|
|
|
2014-02-07 14:52:37 +04:00
|
|
|
return 0;
|
2012-10-16 15:14:04 +04:00
|
|
|
}
|
|
|
|
|
2008-07-09 12:10:00 +04:00
|
|
|
/* query the statedb, caller must free the memory */
|
2013-07-04 12:28:19 +04:00
|
|
|
c_strlist_t *csync_statedb_query(sqlite3 *db,
|
2013-06-26 01:14:08 +04:00
|
|
|
const char *statement) {
|
2008-12-23 15:54:57 +03:00
|
|
|
int err = SQLITE_OK;
|
|
|
|
int rc = SQLITE_OK;
|
2008-02-27 20:56:47 +03:00
|
|
|
size_t i = 0;
|
|
|
|
size_t busy_count = 0;
|
|
|
|
size_t retry_count = 0;
|
|
|
|
size_t column_count = 0;
|
|
|
|
sqlite3_stmt *stmt;
|
|
|
|
const char *tail = NULL;
|
2013-11-14 17:37:43 +04:00
|
|
|
const char *field = NULL;
|
2008-02-27 20:56:47 +03:00
|
|
|
c_strlist_t *result = NULL;
|
2012-08-23 18:54:36 +04:00
|
|
|
int row = 0;
|
2008-02-27 20:56:47 +03:00
|
|
|
|
|
|
|
do {
|
|
|
|
/* compile SQL program into a virtual machine, reattempteing if busy */
|
|
|
|
do {
|
|
|
|
if (busy_count) {
|
|
|
|
/* sleep 100 msec */
|
|
|
|
usleep(100000);
|
2008-06-27 20:52:09 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "sqlite3_prepare: BUSY counter: %zu", busy_count);
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
2013-06-26 01:14:08 +04:00
|
|
|
err = sqlite3_prepare(db, statement, -1, &stmt, &tail);
|
2008-02-27 20:56:47 +03:00
|
|
|
} while (err == SQLITE_BUSY && busy_count ++ < 120);
|
|
|
|
|
|
|
|
if (err != SQLITE_OK) {
|
|
|
|
if (err == SQLITE_BUSY) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Gave up waiting for lock to clear");
|
|
|
|
}
|
2013-06-26 01:14:08 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN,
|
|
|
|
"sqlite3_compile error: %s - on query %s",
|
|
|
|
sqlite3_errmsg(db), statement);
|
2008-02-27 20:56:47 +03:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
busy_count = 0;
|
|
|
|
column_count = sqlite3_column_count(stmt);
|
|
|
|
|
|
|
|
/* execute virtual machine by iterating over rows */
|
|
|
|
for(;;) {
|
|
|
|
err = sqlite3_step(stmt);
|
|
|
|
|
|
|
|
if (err == SQLITE_BUSY) {
|
|
|
|
if (busy_count++ > 120) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Busy counter has reached its maximum. Aborting this sql statement");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* sleep 100 msec */
|
|
|
|
usleep(100000);
|
2008-06-27 20:52:09 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_step: BUSY counter: %zu", busy_count);
|
2008-02-27 20:56:47 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err == SQLITE_MISUSE) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite3_step: MISUSE!!");
|
|
|
|
}
|
|
|
|
|
2008-04-29 13:41:16 +04:00
|
|
|
if (err == SQLITE_DONE) {
|
|
|
|
if (result == NULL) {
|
|
|
|
result = c_strlist_new(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err == SQLITE_ERROR) {
|
2008-02-27 20:56:47 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-10-27 21:27:14 +04:00
|
|
|
row++;
|
2012-08-23 18:54:36 +04:00
|
|
|
if( result ) {
|
|
|
|
result = c_strlist_expand(result, row*column_count);
|
|
|
|
} else {
|
|
|
|
result = c_strlist_new(column_count);
|
|
|
|
}
|
|
|
|
|
2008-02-27 20:56:47 +03:00
|
|
|
if (result == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* iterate over columns */
|
|
|
|
for (i = 0; i < column_count; i++) {
|
2013-11-14 17:37:43 +04:00
|
|
|
field = (const char *) sqlite3_column_text(stmt, i);
|
|
|
|
if (!field)
|
|
|
|
field = "";
|
|
|
|
// CSYNC_LOG(CSYNC_LOG_PRIORITY_TRACE, "sqlite3_column_text: %s", field);
|
|
|
|
if (c_strlist_add(result, field) < 0) {
|
2008-02-27 20:56:47 +03:00
|
|
|
c_strlist_destroy(result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* end infinite for loop */
|
|
|
|
|
|
|
|
/* deallocate vm resources */
|
|
|
|
rc = sqlite3_finalize(stmt);
|
|
|
|
|
|
|
|
if (err != SQLITE_DONE && rc != SQLITE_SCHEMA) {
|
2013-06-26 01:14:08 +04:00
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "sqlite_step error: %s - on query: %s", sqlite3_errmsg(db), statement);
|
2012-10-19 22:09:00 +04:00
|
|
|
if (result != NULL) {
|
|
|
|
c_strlist_destroy(result);
|
|
|
|
}
|
2013-05-13 13:57:25 +04:00
|
|
|
return NULL;
|
2008-02-27 20:56:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == SQLITE_SCHEMA) {
|
|
|
|
retry_count ++;
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "SQLITE_SCHEMA error occurred on query: %s", statement);
|
|
|
|
if (retry_count < 10) {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Retrying now.");
|
|
|
|
} else {
|
|
|
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "RETRY count has reached its maximum. Aborting statement: %s", statement);
|
2012-10-19 22:09:00 +04:00
|
|
|
if (result != NULL) {
|
|
|
|
c_strlist_destroy(result);
|
|
|
|
}
|
2008-02-27 20:56:47 +03:00
|
|
|
result = c_strlist_new(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (rc == SQLITE_SCHEMA && retry_count < 10);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-05-13 12:12:07 +04:00
|
|
|
/* vim: set ts=8 sw=2 et cindent: */
|