/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2014 Martin Raiber * * 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, either version 3 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **************************************************************************/ #include "ServerBackupDao.h" #include "../../stringtools.h" #include #include /** * @-SQLGenTempSetup * @sql * CREATE TEMPORARY TABLE files_last ( fullpath TEXT, hashpath TEXT, shahash BLOB, filesize INTEGER); */ /** * @-SQLGenTempSetup * @sql * CREATE TEMPORARY TABLE files_new_tmp ( fullpath TEXT, hashpath TEXT, shahash BLOB, filesize INTEGER, created DATE DEFAULT CURRENT_TIMESTAMP ); */ ServerBackupDao::ServerBackupDao( IDatabase *db ) : db(db) { prepareQueries(); } ServerBackupDao::~ServerBackupDao() { destroyQueries(); } /** * @-SQLGenAccess * @func void ServerBackupDao::addDirectoryLink * @sql * INSERT INTO directory_links * (clientid, name, target) * VALUES * (:clientid(int), * :name(string), * :target(string)) */ void ServerBackupDao::addDirectoryLink(int clientid, const std::wstring& name, const std::wstring& target) { if(q_addDirectoryLink==NULL) { q_addDirectoryLink=db->Prepare("INSERT INTO directory_links (clientid, name, target) VALUES (?, ?, ?)", false); } q_addDirectoryLink->Bind(clientid); q_addDirectoryLink->Bind(name); q_addDirectoryLink->Bind(target); q_addDirectoryLink->Write(); q_addDirectoryLink->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::removeDirectoryLink * @sql * DELETE FROM directory_links * WHERE clientid=:clientid(int) * AND target=:target(string) */ void ServerBackupDao::removeDirectoryLink(int clientid, const std::wstring& target) { if(q_removeDirectoryLink==NULL) { q_removeDirectoryLink=db->Prepare("DELETE FROM directory_links WHERE clientid=? AND target=?", false); } q_removeDirectoryLink->Bind(clientid); q_removeDirectoryLink->Bind(target); q_removeDirectoryLink->Write(); q_removeDirectoryLink->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::removeDirectoryLinkGlob * @sql * DELETE FROM directory_links * WHERE clientid=:clientid(int) * AND target GLOB :target(string) */ void ServerBackupDao::removeDirectoryLinkGlob(int clientid, const std::wstring& target) { if(q_removeDirectoryLinkGlob==NULL) { q_removeDirectoryLinkGlob=db->Prepare("DELETE FROM directory_links WHERE clientid=? AND target GLOB ?", false); } q_removeDirectoryLinkGlob->Bind(clientid); q_removeDirectoryLinkGlob->Bind(target); q_removeDirectoryLinkGlob->Write(); q_removeDirectoryLinkGlob->Reset(); } /** * @-SQLGenAccess * @func int ServerBackupDao::getDirectoryRefcount * @return int_raw c * @sql * SELECT COUNT(*) AS c FROM directory_links * WHERE clientid=:clientid(int) * AND name=:name(string) * LIMIT 1 */ int ServerBackupDao::getDirectoryRefcount(int clientid, const std::wstring& name) { if(q_getDirectoryRefcount==NULL) { q_getDirectoryRefcount=db->Prepare("SELECT COUNT(*) AS c FROM directory_links WHERE clientid=? AND name=? LIMIT 1", false); } q_getDirectoryRefcount->Bind(clientid); q_getDirectoryRefcount->Bind(name); db_results res=q_getDirectoryRefcount->Read(); q_getDirectoryRefcount->Reset(); assert(!res.empty()); return watoi(res[0][L"c"]); } /** * @-SQLGenAccess * @func void ServerBackupDao::addDirectoryLinkJournalEntry * @sql * INSERT INTO directory_link_journal (linkname, linktarget) * VALUES (:linkname(string), :linktarget(string)) */ void ServerBackupDao::addDirectoryLinkJournalEntry(const std::wstring& linkname, const std::wstring& linktarget) { if(q_addDirectoryLinkJournalEntry==NULL) { q_addDirectoryLinkJournalEntry=db->Prepare("INSERT INTO directory_link_journal (linkname, linktarget) VALUES (?, ?)", false); } q_addDirectoryLinkJournalEntry->Bind(linkname); q_addDirectoryLinkJournalEntry->Bind(linktarget); q_addDirectoryLinkJournalEntry->Write(); q_addDirectoryLinkJournalEntry->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::removeDirectoryLinkJournalEntry * @sql * DELETE FROM directory_link_journal WHERE * id = :entry_id(int64) */ void ServerBackupDao::removeDirectoryLinkJournalEntry(int64 entry_id) { if(q_removeDirectoryLinkJournalEntry==NULL) { q_removeDirectoryLinkJournalEntry=db->Prepare("DELETE FROM directory_link_journal WHERE id = ?", false); } q_removeDirectoryLinkJournalEntry->Bind(entry_id); q_removeDirectoryLinkJournalEntry->Write(); q_removeDirectoryLinkJournalEntry->Reset(); } /** * @-SQLGenAccess * @func vector ServerBackupDao::getDirectoryLinkJournalEntries * @return string linkname, string linktarget * @sql * SELECT linkname, linktarget FROM directory_link_journal */ std::vector ServerBackupDao::getDirectoryLinkJournalEntries(void) { if(q_getDirectoryLinkJournalEntries==NULL) { q_getDirectoryLinkJournalEntries=db->Prepare("SELECT linkname, linktarget FROM directory_link_journal", false); } db_results res=q_getDirectoryLinkJournalEntries->Read(); std::vector ret; ret.resize(res.size()); for(size_t i=0;iPrepare("DELETE FROM directory_link_journal", false); } q_removeDirectoryLinkJournalEntries->Write(); } /** * @-SQLGenAccess * @func vector ServerBackupDao::getLinksInDirectory * @return string name, string target * @sql * SELECT name, target FROM directory_links * WHERE clientid=:clientid(int) AND * target GLOB :dir(string) */ std::vector ServerBackupDao::getLinksInDirectory(int clientid, const std::wstring& dir) { if(q_getLinksInDirectory==NULL) { q_getLinksInDirectory=db->Prepare("SELECT name, target FROM directory_links WHERE clientid=? AND target GLOB ?", false); } q_getLinksInDirectory->Bind(clientid); q_getLinksInDirectory->Bind(dir); db_results res=q_getLinksInDirectory->Read(); q_getLinksInDirectory->Reset(); std::vector ret; ret.resize(res.size()); for(size_t i=0;iPrepare("DELETE FROM directory_links WHERE id=?", false); } q_deleteLinkReferenceEntry->Bind(id); q_deleteLinkReferenceEntry->Write(); q_deleteLinkReferenceEntry->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::updateLinkReferenceTarget * @sql * UPDATE directory_links SET target=:new_target(string) * WHERE id=:id(int64) */ void ServerBackupDao::updateLinkReferenceTarget(const std::wstring& new_target, int64 id) { if(q_updateLinkReferenceTarget==NULL) { q_updateLinkReferenceTarget=db->Prepare("UPDATE directory_links SET target=? WHERE id=?", false); } q_updateLinkReferenceTarget->Bind(new_target); q_updateLinkReferenceTarget->Bind(id); q_updateLinkReferenceTarget->Write(); q_updateLinkReferenceTarget->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::addToOldBackupfolders * @sql * INSERT OR REPLACE INTO settings_db.old_backupfolders (backupfolder) * VALUES (:backupfolder(string)) */ void ServerBackupDao::addToOldBackupfolders(const std::wstring& backupfolder) { if(q_addToOldBackupfolders==NULL) { q_addToOldBackupfolders=db->Prepare("INSERT OR REPLACE INTO settings_db.old_backupfolders (backupfolder) VALUES (?)", false); } q_addToOldBackupfolders->Bind(backupfolder); q_addToOldBackupfolders->Write(); q_addToOldBackupfolders->Reset(); } /** * @-SQLGenAccess * @func vector ServerBackupDao::getOldBackupfolders * @return string backupfolder * @sql * SELECT backupfolder FROM settings_db.old_backupfolders */ std::vector ServerBackupDao::getOldBackupfolders(void) { if(q_getOldBackupfolders==NULL) { q_getOldBackupfolders=db->Prepare("SELECT backupfolder FROM settings_db.old_backupfolders", false); } db_results res=q_getOldBackupfolders->Read(); std::vector ret; ret.resize(res.size()); for(size_t i=0;i ServerBackupDao::getDeletePendingClientNames * @return string name * @sql * SELECT name FROM clients WHERE delete_pending=1 */ std::vector ServerBackupDao::getDeletePendingClientNames(void) { if(q_getDeletePendingClientNames==NULL) { q_getDeletePendingClientNames=db->Prepare("SELECT name FROM clients WHERE delete_pending=1", false); } db_results res=q_getDeletePendingClientNames->Read(); std::vector ret; ret.resize(res.size()); for(size_t i=0;iPrepare("CREATE TEMPORARY TABLE files_last ( fullpath TEXT, hashpath TEXT, shahash BLOB, filesize INTEGER, created DATE, rsize INTEGER );", false); } bool ret = q_createTemporaryLastFilesTable->Write(); return ret; } /** * @-SQLGenAccessNoCheck * @func void ServerBackupDao::dropTemporaryLastFilesTable * @sql * DROP TABLE files_last */ void ServerBackupDao::dropTemporaryLastFilesTable(void) { if(q_dropTemporaryLastFilesTable==NULL) { q_dropTemporaryLastFilesTable=db->Prepare("DROP TABLE files_last", false); } q_dropTemporaryLastFilesTable->Write(); } /** * @-SQLGenAccessNoCheck * @func bool ServerBackupDao::createTemporaryLastFilesTableIndex * @sql * CREATE INDEX files_last_idx ON files_last ( fullpath ); */ bool ServerBackupDao::createTemporaryLastFilesTableIndex(void) { if(q_createTemporaryLastFilesTableIndex==NULL) { q_createTemporaryLastFilesTableIndex=db->Prepare("CREATE INDEX files_last_idx ON files_last ( fullpath );", false); } bool ret = q_createTemporaryLastFilesTableIndex->Write(); return ret; } /** * @-SQLGenAccessNoCheck * @func bool ServerBackupDao::dropTemporaryLastFilesTableIndex * @sql * DROP INDEX files_last_idx; */ bool ServerBackupDao::dropTemporaryLastFilesTableIndex(void) { if(q_dropTemporaryLastFilesTableIndex==NULL) { q_dropTemporaryLastFilesTableIndex=db->Prepare("DROP INDEX files_last_idx;", false); } bool ret = q_dropTemporaryLastFilesTableIndex->Write(); return ret; } /** * @-SQLGenAccess * @func bool ServerBackupDao::copyToTemporaryLastFilesTable * @sql * INSERT INTO files_last (fullpath, hashpath, shahash, filesize) * SELECT fullpath, hashpath, shahash, filesize FROM files * WHERE backupid = :backupid(int) */ bool ServerBackupDao::copyToTemporaryLastFilesTable(int backupid) { if(q_copyToTemporaryLastFilesTable==NULL) { q_copyToTemporaryLastFilesTable=db->Prepare("INSERT INTO files_last (fullpath, hashpath, shahash, filesize) SELECT fullpath, hashpath, shahash, filesize FROM files WHERE backupid = ?", false); } q_copyToTemporaryLastFilesTable->Bind(backupid); bool ret = q_copyToTemporaryLastFilesTable->Write(); q_copyToTemporaryLastFilesTable->Reset(); return ret; } /** * @-SQLGenAccess * @func SFileEntry ServerBackupDao::getFileEntryFromTemporaryTable * @return string fullpath, string hashpath, blob shahash, int64 filesize * @sql * SELECT fullpath, hashpath, shahash, filesize * FROM files_last WHERE fullpath = :fullpath(string) */ ServerBackupDao::SFileEntry ServerBackupDao::getFileEntryFromTemporaryTable(const std::wstring& fullpath) { if(q_getFileEntryFromTemporaryTable==NULL) { q_getFileEntryFromTemporaryTable=db->Prepare("SELECT fullpath, hashpath, shahash, filesize FROM files_last WHERE fullpath = ?", false); } q_getFileEntryFromTemporaryTable->Bind(fullpath); db_results res=q_getFileEntryFromTemporaryTable->Read(); q_getFileEntryFromTemporaryTable->Reset(); SFileEntry ret = { false, L"", L"", "", 0 }; if(!res.empty()) { ret.exists=true; ret.fullpath=res[0][L"fullpath"]; ret.hashpath=res[0][L"hashpath"]; std::wstring& val1 = res[0][L"shahash"]; ret.shahash.resize(val1.size()*sizeof(wchar_t)); memcpy(&ret.shahash[0], val1.data(), val1.size()*sizeof(wchar_t)); ret.filesize=watoi64(res[0][L"filesize"]); } return ret; } /** * @-SQLGenAccess * @func vector ServerBackupDao::getFileEntriesFromTemporaryTableGlob * @return string fullpath, string hashpath, blob shahash, int64 filesize * @sql * SELECT fullpath, hashpath, shahash, filesize * FROM files_last WHERE fullpath GLOB :fullpath_glob(string) */ std::vector ServerBackupDao::getFileEntriesFromTemporaryTableGlob(const std::wstring& fullpath_glob) { if(q_getFileEntriesFromTemporaryTableGlob==NULL) { q_getFileEntriesFromTemporaryTableGlob=db->Prepare("SELECT fullpath, hashpath, shahash, filesize FROM files_last WHERE fullpath GLOB ?", false); } q_getFileEntriesFromTemporaryTableGlob->Bind(fullpath_glob); db_results res=q_getFileEntriesFromTemporaryTableGlob->Read(); q_getFileEntriesFromTemporaryTableGlob->Reset(); std::vector ret; ret.resize(res.size()); for(size_t i=0;iPrepare("CREATE TEMPORARY TABLE files_new_tmp ( fullpath TEXT, hashpath TEXT, shahash BLOB, filesize INTEGER, created DATE DEFAULT CURRENT_TIMESTAMP );", false); } bool ret = q_createTemporaryNewFilesTable->Write(); return ret; } /** * @-SQLGenAccessNoCheck * @func void ServerBackupDao::dropTemporaryNewFilesTable * @sql * DROP TABLE files_new_tmp */ void ServerBackupDao::dropTemporaryNewFilesTable(void) { if(q_dropTemporaryNewFilesTable==NULL) { q_dropTemporaryNewFilesTable=db->Prepare("DROP TABLE files_new_tmp", false); } q_dropTemporaryNewFilesTable->Write(); } /** * @-SQLGenAccess * @func void ServerBackupDao::insertIntoTemporaryNewFilesTable * @sql * INSERT INTO files_new_tmp ( fullpath, hashpath, shahash, filesize) * VALUES ( :fullpath(string), :hashpath(string), :shahash(blob), :filesize(int64) ) */ void ServerBackupDao::insertIntoTemporaryNewFilesTable(const std::wstring& fullpath, const std::wstring& hashpath, const std::string& shahash, int64 filesize) { if(q_insertIntoTemporaryNewFilesTable==NULL) { q_insertIntoTemporaryNewFilesTable=db->Prepare("INSERT INTO files_new_tmp ( fullpath, hashpath, shahash, filesize) VALUES ( ?, ?, ?, ? )", false); } q_insertIntoTemporaryNewFilesTable->Bind(fullpath); q_insertIntoTemporaryNewFilesTable->Bind(hashpath); q_insertIntoTemporaryNewFilesTable->Bind(shahash.c_str(), (_u32)shahash.size()); q_insertIntoTemporaryNewFilesTable->Bind(filesize); q_insertIntoTemporaryNewFilesTable->Write(); q_insertIntoTemporaryNewFilesTable->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::copyFromTemporaryNewFilesTable * @sql * INSERT INTO files (backupid, fullpath, hashpath, shahash, filesize, created, rsize, did_count, clientid, incremental) * SELECT :backupid(int) AS backupid, fullpath, hashpath, * shahash, filesize, created, 0 AS rsize, 0 AS did_count, :clientid(int) AS clientid, * :incremental(int) AS incremental FROM files_new_tmp */ void ServerBackupDao::copyFromTemporaryNewFilesTable(int backupid, int clientid, int incremental) { if(q_copyFromTemporaryNewFilesTable==NULL) { q_copyFromTemporaryNewFilesTable=db->Prepare("INSERT INTO files (backupid, fullpath, hashpath, shahash, filesize, created, rsize, did_count, clientid, incremental) SELECT ? AS backupid, fullpath, hashpath, shahash, filesize, created, 0 AS rsize, 0 AS did_count, ? AS clientid, ? AS incremental FROM files_new_tmp", false); } q_copyFromTemporaryNewFilesTable->Bind(backupid); q_copyFromTemporaryNewFilesTable->Bind(clientid); q_copyFromTemporaryNewFilesTable->Bind(incremental); q_copyFromTemporaryNewFilesTable->Write(); q_copyFromTemporaryNewFilesTable->Reset(); } /** * @-SQLGenAccess * @func void ServerBackupDao::insertIntoOrigClientSettings * @sql * INSERT OR REPLACE INTO orig_client_settings (clientid, data) * VALUES (:clientid(int), :data(std::string)) */ void ServerBackupDao::insertIntoOrigClientSettings(int clientid, std::string data) { if(q_insertIntoOrigClientSettings==NULL) { q_insertIntoOrigClientSettings=db->Prepare("INSERT OR REPLACE INTO orig_client_settings (clientid, data) VALUES (?, ?)", false); } q_insertIntoOrigClientSettings->Bind(clientid); q_insertIntoOrigClientSettings->Bind(data); q_insertIntoOrigClientSettings->Write(); q_insertIntoOrigClientSettings->Reset(); } /** * @-SQLGenAccess * @func string ServerBackupDao::getOrigClientSettings * @return string data * @sql * SELECT data FROM orig_client_settings WHERE clientid = :clientid(int) */ ServerBackupDao::CondString ServerBackupDao::getOrigClientSettings(int clientid) { if(q_getOrigClientSettings==NULL) { q_getOrigClientSettings=db->Prepare("SELECT data FROM orig_client_settings WHERE clientid = ?", false); } q_getOrigClientSettings->Bind(clientid); db_results res=q_getOrigClientSettings->Read(); q_getOrigClientSettings->Reset(); CondString ret = { false, L"" }; if(!res.empty()) { ret.exists=true; ret.value=res[0][L"data"]; } return ret; } /** * @-SQLGenAccess * @func vector ServerBackupDao::getLastIncrementalDurations * @return int64 indexing_time_ms, int64 duration * @sql * SELECT indexing_time_ms, (strftime('%s',running)-strftime('%s',backuptime)) AS duration * FROM backups * WHERE clientid=:clientid(int) AND done=1 AND complete=1 AND incremental<>0 AND resumed=0 * ORDER BY backuptime DESC LIMIT 10 */ std::vector ServerBackupDao::getLastIncrementalDurations(int clientid) { if(q_getLastIncrementalDurations==NULL) { q_getLastIncrementalDurations=db->Prepare("SELECT indexing_time_ms, (strftime('%s',running)-strftime('%s',backuptime)) AS duration FROM backups WHERE clientid=? AND done=1 AND complete=1 AND incremental<>0 AND resumed=0 ORDER BY backuptime DESC LIMIT 10", false); } q_getLastIncrementalDurations->Bind(clientid); db_results res=q_getLastIncrementalDurations->Read(); q_getLastIncrementalDurations->Reset(); std::vector ret; ret.resize(res.size()); for(size_t i=0;i ServerBackupDao::getLastFullDurations * @return int64 indexing_time_ms, int64 duration * @sql * SELECT indexing_time_ms, (strftime('%s',running)-strftime('%s',backuptime)) AS duration * FROM backups * WHERE clientid=:clientid(int) AND done=1 AND complete=1 AND incremental=0 AND resumed=0 * ORDER BY backuptime DESC LIMIT 1 */ std::vector ServerBackupDao::getLastFullDurations(int clientid) { if(q_getLastFullDurations==NULL) { q_getLastFullDurations=db->Prepare("SELECT indexing_time_ms, (strftime('%s',running)-strftime('%s',backuptime)) AS duration FROM backups WHERE clientid=? AND done=1 AND complete=1 AND incremental=0 AND resumed=0 ORDER BY backuptime DESC LIMIT 1", false); } q_getLastFullDurations->Bind(clientid); db_results res=q_getLastFullDurations->Read(); q_getLastFullDurations->Reset(); std::vector ret; ret.resize(res.size()); for(size_t i=0;idestroyQuery(q_addDirectoryLink); db->destroyQuery(q_removeDirectoryLink); db->destroyQuery(q_removeDirectoryLinkGlob); db->destroyQuery(q_getDirectoryRefcount); db->destroyQuery(q_addDirectoryLinkJournalEntry); db->destroyQuery(q_removeDirectoryLinkJournalEntry); db->destroyQuery(q_getDirectoryLinkJournalEntries); db->destroyQuery(q_removeDirectoryLinkJournalEntries); db->destroyQuery(q_getLinksInDirectory); db->destroyQuery(q_deleteLinkReferenceEntry); db->destroyQuery(q_updateLinkReferenceTarget); db->destroyQuery(q_addToOldBackupfolders); db->destroyQuery(q_getOldBackupfolders); db->destroyQuery(q_getDeletePendingClientNames); db->destroyQuery(q_createTemporaryLastFilesTable); db->destroyQuery(q_dropTemporaryLastFilesTable); db->destroyQuery(q_createTemporaryLastFilesTableIndex); db->destroyQuery(q_dropTemporaryLastFilesTableIndex); db->destroyQuery(q_copyToTemporaryLastFilesTable); db->destroyQuery(q_getFileEntryFromTemporaryTable); db->destroyQuery(q_getFileEntriesFromTemporaryTableGlob); db->destroyQuery(q_createTemporaryNewFilesTable); db->destroyQuery(q_dropTemporaryNewFilesTable); db->destroyQuery(q_insertIntoTemporaryNewFilesTable); db->destroyQuery(q_copyFromTemporaryNewFilesTable); db->destroyQuery(q_insertIntoOrigClientSettings); db->destroyQuery(q_getOrigClientSettings); db->destroyQuery(q_getLastIncrementalDurations); db->destroyQuery(q_getLastFullDurations); } void ServerBackupDao::commit() { db->Write("PRAGMA wal_checkpoint"); } int64 ServerBackupDao::getLastId() { return db->getLastInsertID(); }