void ActionLog::LookupRecentFileActions(const function<void(const std::string&, int, int)>& visitor, int limit) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT AL.filename, AL.action" " FROM ActionLog AL" " JOIN " " (SELECT filename, MAX(action_timestamp) AS action_timestamp " " FROM ActionLog " " GROUP BY filename ) AS GAL" " ON AL.filename = GAL.filename AND AL.action_timestamp = GAL.action_timestamp " " ORDER BY AL.action_timestamp DESC " " LIMIT ?;", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_int(stmt, 1, limit); int index = 0; while (sqlite3_step(stmt) == SQLITE_ROW) { std::string filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 0)); int action = sqlite3_column_int(stmt, 1); visitor(filename, action, index); index++; } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); }
FileItemsPtr FileState::LookupFilesForHash(const Buffer& hash) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT filename,version,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete " " FROM FileState " " WHERE type = 0 AND file_hash = ?", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_blob(stmt, 1, hash.buf(), hash.size(), SQLITE_STATIC); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); FileItemsPtr retval = make_shared<FileItems>(); while (sqlite3_step(stmt) == SQLITE_ROW) { FileItem file; file.set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 0)); file.set_version(sqlite3_column_int64(stmt, 1)); file.set_device_name(sqlite3_column_blob(stmt, 2), sqlite3_column_bytes(stmt, 2)); file.set_seq_no(sqlite3_column_int64(stmt, 3)); file.set_file_hash(sqlite3_column_blob(stmt, 4), sqlite3_column_bytes(stmt, 4)); file.set_mtime(sqlite3_column_int(stmt, 5)); file.set_mode(sqlite3_column_int(stmt, 6)); file.set_seg_num(sqlite3_column_int64(stmt, 7)); file.set_is_complete(sqlite3_column_int(stmt, 8)); retval->push_back(file); } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); return retval; }
/** * @todo Implement checking modification time and permissions */ FileItemPtr FileState::LookupFile(const std::string& filename) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT filename,version,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete " " FROM FileState " " WHERE type = 0 AND filename = ?", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); FileItemPtr retval; if (sqlite3_step(stmt) == SQLITE_ROW) { retval = make_shared<FileItem>(); retval->set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 0)); retval->set_version(sqlite3_column_int64(stmt, 1)); retval->set_device_name(sqlite3_column_blob(stmt, 2), sqlite3_column_bytes(stmt, 2)); retval->set_seq_no(sqlite3_column_int64(stmt, 3)); retval->set_file_hash(sqlite3_column_blob(stmt, 4), sqlite3_column_bytes(stmt, 4)); retval->set_mtime(sqlite3_column_int(stmt, 5)); retval->set_mode(sqlite3_column_int(stmt, 6)); retval->set_seg_num(sqlite3_column_int64(stmt, 7)); retval->set_is_complete(sqlite3_column_int(stmt, 8)); } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); return retval; }
void FileState::SetFileComplete(const std::string& filename) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "UPDATE FileState SET is_complete=1 WHERE type = 0 AND filename = ?", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); }
shared_ptr<Data> ActionLog::LookupActionData(const Name& actionName) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT action_content_object FROM ActionLog WHERE action_name=?", -1, &stmt, 0); _LOG_DEBUG(actionName); _LOG_DEBUG(" LookActionData <<<<<<< " << actionName << " " << actionName.wireEncode().size()); sqlite3_bind_blob(stmt, 1, actionName.wireEncode().wire(), actionName.wireEncode().size(), SQLITE_STATIC); shared_ptr<Data> retval; // = make_shared<Data>(); if (sqlite3_step(stmt) == SQLITE_ROW) { // _LOG_DEBUG(sqlite3_column_blob(stmt, 0) << ", " << sqlite3_column_bytes(stmt, 0)); retval = make_shared<Data>(); retval->wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 0)), sqlite3_column_bytes(stmt, 0))); } else { _LOG_TRACE("No action found for name: " << actionName); } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_ROW, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); return retval; }
void FileState::DeleteFile(const std::string& filename) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "DELETE FROM FileState WHERE type=0 AND filename=?", -1, &stmt, 0); sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); _LOG_DEBUG("Delete " << filename); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); }
FileItemPtr ActionLog::LookupAction(const std::string& filename, sqlite3_int64 version, const Buffer& filehash) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT device_name, seq_no, strftime('%s', file_mtime), file_chmod, file_seg_num, file_hash " " FROM ActionLog " " WHERE action = 0 AND " " filename=? AND " " version=? AND " " is_prefix(?, file_hash)=1", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, version); sqlite3_bind_blob(stmt, 3, filehash.buf(), filehash.size(), SQLITE_STATIC); FileItemPtr fileItem; if (sqlite3_step(stmt) == SQLITE_ROW) { fileItem = make_shared<FileItem>(); fileItem->set_filename(filename); fileItem->set_device_name(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0)); fileItem->set_seq_no(sqlite3_column_int64(stmt, 1)); fileItem->set_mtime(sqlite3_column_int64(stmt, 2)); fileItem->set_mode(sqlite3_column_int64(stmt, 3)); fileItem->set_seg_num(sqlite3_column_int64(stmt, 4)); fileItem->set_file_hash(sqlite3_column_blob(stmt, 5), sqlite3_column_bytes(stmt, 5)); } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE || sqlite3_errcode(m_db) != SQLITE_ROW || sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); return fileItem; }
void FileState::LookupFilesInFolder(const function<void(const FileItem&)>& visitor, const std::string& folder, int offset /*=0*/, int limit /*=-1*/) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT filename,version,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete " " FROM FileState " " WHERE type = 0 AND directory = ?" " LIMIT ? OFFSET ?", -1, &stmt, 0); if (folder.size() == 0) sqlite3_bind_null(stmt, 1); else sqlite3_bind_text(stmt, 1, folder.c_str(), folder.size(), SQLITE_STATIC); sqlite3_bind_int(stmt, 2, limit); sqlite3_bind_int(stmt, 3, offset); while (sqlite3_step(stmt) == SQLITE_ROW) { FileItem file; file.set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 0)); file.set_version(sqlite3_column_int64(stmt, 1)); file.set_device_name(sqlite3_column_blob(stmt, 2), sqlite3_column_bytes(stmt, 2)); file.set_seq_no(sqlite3_column_int64(stmt, 3)); file.set_file_hash(sqlite3_column_blob(stmt, 4), sqlite3_column_bytes(stmt, 4)); file.set_mtime(sqlite3_column_int(stmt, 5)); file.set_mode(sqlite3_column_int(stmt, 6)); file.set_seg_num(sqlite3_column_int64(stmt, 7)); file.set_is_complete(sqlite3_column_int(stmt, 8)); visitor(file); } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); }
/** * @todo Figure out the way to minimize code duplication */ bool ActionLog::LookupActionsForFile( const function<void(const Name& name, sqlite3_int64 seq_no, const ActionItem&)>& visitor, const std::string& file, int offset /*=0*/, int limit /*=-1*/) { _LOG_DEBUG("LookupActionsInFolderRecursively: [" << file << "]"); if (file.empty()) return false; if (limit >= 0) limit += 1; // to check if there is more data sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "SELECT device_name,seq_no,action,filename,directory,version,strftime('%s', action_timestamp), " " file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num, " " parent_device_name,parent_seq_no " " FROM ActionLog " " WHERE filename=? " " ORDER BY action_timestamp DESC " " LIMIT ? OFFSET ?", -1, &stmt, 0); // there is a small ambiguity with is_prefix matching, but should be ok for now _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, file.c_str(), file.size(), SQLITE_STATIC); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_int(stmt, 2, limit); sqlite3_bind_int(stmt, 3, offset); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); while (sqlite3_step(stmt) == SQLITE_ROW) { if (limit == 1) break; ActionItem action; Name device_name(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, 0)), sqlite3_column_bytes(stmt, 0))); sqlite3_int64 seq_no = sqlite3_column_int64(stmt, 1); action.set_action(static_cast<ActionItem_ActionType>(sqlite3_column_int(stmt, 2))); action.set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)), sqlite3_column_bytes(stmt, 3)); std::string directory(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4)), sqlite3_column_bytes(stmt, 4)); action.set_version(sqlite3_column_int64(stmt, 5)); action.set_timestamp(sqlite3_column_int64(stmt, 6)); if (action.action() == 0) { action.set_file_hash(sqlite3_column_blob(stmt, 7), sqlite3_column_bytes(stmt, 7)); action.set_mtime(sqlite3_column_int(stmt, 8)); action.set_mode(sqlite3_column_int(stmt, 9)); action.set_seg_num(sqlite3_column_int64(stmt, 10)); } if (sqlite3_column_bytes(stmt, 11) > 0) { action.set_parent_device_name(sqlite3_column_blob(stmt, 11), sqlite3_column_bytes(stmt, 11)); action.set_parent_seq_no(sqlite3_column_int64(stmt, 12)); } visitor(device_name, seq_no, action); limit--; } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); return (limit == 1); // more data is available }
ActionItemPtr ActionLog::AddRemoteAction(const Name& deviceName, sqlite3_int64 seqno, shared_ptr<Data> actionData) { if (!actionData) { _LOG_ERROR("actionData is not valid"); return ActionItemPtr(); } ActionItemPtr action = deserializeMsg<ActionItem>( Buffer(actionData->getContent().value(), actionData->getContent().value_size())); if (!action) { _LOG_ERROR("action cannot be decoded"); return ActionItemPtr(); } _LOG_DEBUG("AddRemoteAction: [" << deviceName.toUri() << "] seqno: " << seqno); sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "INSERT INTO ActionLog " "(device_name, seq_no, action, filename, version, action_timestamp, " "file_hash, file_atime, file_mtime, file_ctime, file_chmod, file_seg_num, " "parent_device_name, parent_seq_no, " "action_name, action_content_object) " "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch')," " ?, datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?,?, " " ?, ?, " " ?, ?);", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_blob(stmt, 1, deviceName.wireEncode().wire(), deviceName.wireEncode().size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, seqno); sqlite3_bind_int(stmt, 3, action->action()); sqlite3_bind_text(stmt, 4, action->filename().c_str(), action->filename().size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 5, action->version()); sqlite3_bind_int64(stmt, 6, action->timestamp()); if (action->action() == ActionItem::UPDATE) { sqlite3_bind_blob(stmt, 7, action->file_hash().c_str(), action->file_hash().size(), SQLITE_STATIC); // sqlite3_bind_int64(stmt, 8, atime); // NULL sqlite3_bind_int64(stmt, 9, action->mtime()); // sqlite3_bind_int64(stmt, 10, ctime); // NULL sqlite3_bind_int(stmt, 11, action->mode()); sqlite3_bind_int(stmt, 12, action->seg_num()); } if (action->has_parent_device_name()) { sqlite3_bind_blob(stmt, 13, action->parent_device_name().c_str(), action->parent_device_name().size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 14, action->parent_seq_no()); } Name actionName = Name(deviceName); actionName.append("action").append(m_sharedFolderName).appendNumber(seqno); sqlite3_bind_blob(stmt, 15, actionName.wireEncode().wire(), actionName.wireEncode().size(), SQLITE_STATIC); sqlite3_bind_blob(stmt, 16, actionData->wireEncode().wire(), actionData->wireEncode().size(), SQLITE_STATIC); sqlite3_step(stmt); // if action needs to be applied to file state, the trigger will take care of it _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); // I had a problem including directory_name assignment as part of the initial insert. sqlite3_prepare_v2(m_db, "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_blob(stmt, 1, deviceName.wireEncode().wire(), deviceName.wireEncode().size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, seqno); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); return action; }
ActionItemPtr ActionLog::AddLocalActionDelete(const std::string& filename) { _LOG_DEBUG("Adding local action DELETE"); sqlite3_exec(m_db, "BEGIN TRANSACTION;", 0, 0, 0); const Block device_name = m_syncLog->GetLocalName().wireEncode(); sqlite3_int64 version; BufferPtr parent_device_name; sqlite3_int64 parent_seq_no = -1; sqlite3_int64 action_time = std::time(0); tie(version, parent_device_name, parent_seq_no) = GetLatestActionForFile(filename); if (!parent_device_name) // no records exist or file was already deleted { _LOG_DEBUG("Nothing to delete... [" << filename << "]"); // just in case, remove data from FileState sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "DELETE FROM FileState WHERE filename = ? ", -1, &stmt, 0); sqlite3_bind_text(stmt, 1, filename.c_str(), filename.size(), SQLITE_STATIC); // file sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); sqlite3_exec(m_db, "END TRANSACTION;", 0, 0, 0); return ActionItemPtr(); } version++; sqlite3_int64 seq_no = m_syncLog->GetNextLocalSeqNo(); sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "INSERT INTO ActionLog " "(device_name, seq_no, action, filename, version, action_timestamp, " "parent_device_name, parent_seq_no, " "action_name, action_content_object) " "VALUES(?, ?, ?, ?, ?, datetime(?, 'unixepoch')," " ?, ?," " ?, ?)", -1, &stmt, 0); sqlite3_bind_blob(stmt, 1, device_name.wire(), device_name.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, seq_no); sqlite3_bind_int(stmt, 3, 1); sqlite3_bind_text(stmt, 4, filename.c_str(), filename.size(), SQLITE_STATIC); // file sqlite3_bind_int64(stmt, 5, version); sqlite3_bind_int64(stmt, 6, action_time); sqlite3_bind_blob(stmt, 7, parent_device_name->buf(), parent_device_name->size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 8, parent_seq_no); ActionItemPtr item = make_shared<ActionItem>(); item->set_action(ActionItem::DELETE); item->set_filename(filename); item->set_version(version); item->set_timestamp(action_time); item->set_parent_device_name(parent_device_name->buf(), parent_device_name->size()); item->set_parent_seq_no(parent_seq_no); std::string item_msg; item->SerializeToString(&item_msg); // action name: /<device_name>/<appname>/action/<shared-folder>/<action-seq> Name actionName = Name("/"); actionName.append(m_syncLog->GetLocalName()).append(m_appName).append("action"); actionName.append(m_sharedFolderName).appendNumber(seq_no); _LOG_DEBUG("ActionName: " << actionName); shared_ptr<Data> actionData = make_shared<Data>(); actionData->setName(actionName); actionData->setFreshnessPeriod(time::seconds(60)); actionData->setContent(reinterpret_cast<const uint8_t*>(item_msg.c_str()), item_msg.size()); m_keyChain.sign(*actionData); sqlite3_bind_blob(stmt, 9, actionName.wireEncode().wire(), actionName.wireEncode().size(), SQLITE_STATIC); sqlite3_bind_blob(stmt, 10, actionData->wireEncode().wire(), actionData->wireEncode().size(), SQLITE_STATIC); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); // cout << Name(parent_device_name) << endl; // assign name to the action, serialize action, and create content object sqlite3_finalize(stmt); // I had a problem including directory_name assignment as part of the initial insert. sqlite3_prepare_v2(m_db, "UPDATE ActionLog SET directory=directory_name(filename) WHERE device_name=? AND seq_no=?", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_blob(stmt, 1, device_name.wire(), device_name.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, seq_no); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); sqlite3_exec(m_db, "END TRANSACTION;", 0, 0, 0); return item; }
void FileState::UpdateFile(const std::string& filename, sqlite3_int64 version, const Buffer& hash, const Buffer& device_name, sqlite3_int64 seq_no, time_t atime, time_t mtime, time_t ctime, int mode, int seg_num) { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "UPDATE FileState " "SET " "device_name=?, seq_no=?, " "version=?," "file_hash=?," "file_atime=datetime(?, 'unixepoch')," "file_mtime=datetime(?, 'unixepoch')," "file_ctime=datetime(?, 'unixepoch')," "file_chmod=?, " "file_seg_num=? " "WHERE type=0 AND filename=?", -1, &stmt, 0); sqlite3_bind_blob(stmt, 1, device_name.buf(), device_name.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, seq_no); sqlite3_bind_int64(stmt, 3, version); sqlite3_bind_blob(stmt, 4, hash.buf(), hash.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 5, atime); sqlite3_bind_int64(stmt, 6, mtime); sqlite3_bind_int64(stmt, 7, ctime); sqlite3_bind_int(stmt, 8, mode); sqlite3_bind_int(stmt, 9, seg_num); sqlite3_bind_text(stmt, 10, filename.c_str(), -1, SQLITE_STATIC); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_ROW && sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); int affected_rows = sqlite3_changes(m_db); if (affected_rows == 0) // file didn't exist { sqlite3_stmt* stmt; sqlite3_prepare_v2(m_db, "INSERT INTO FileState " "(type,filename,version,device_name,seq_no,file_hash," "file_atime,file_mtime,file_ctime,file_chmod,file_seg_num) " "VALUES (0, ?, ?, ?, ?, ?, " "datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), datetime(?, 'unixepoch'), ?, ?)", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); sqlite3_bind_int64(stmt, 2, version); sqlite3_bind_blob(stmt, 3, device_name.buf(), device_name.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 4, seq_no); sqlite3_bind_blob(stmt, 5, hash.buf(), hash.size(), SQLITE_STATIC); sqlite3_bind_int64(stmt, 6, atime); sqlite3_bind_int64(stmt, 7, mtime); sqlite3_bind_int64(stmt, 8, ctime); sqlite3_bind_int(stmt, 9, mode); sqlite3_bind_int(stmt, 10, seg_num); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); sqlite3_prepare_v2(m_db, "UPDATE FileState SET directory=directory_name(filename) WHERE filename=?", -1, &stmt, 0); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, filename.c_str(), -1, SQLITE_STATIC); sqlite3_step(stmt); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); } }
FileState::FileState(const boost::filesystem::path& path) : DbHelper(path / ".chronoshare", "file-state.db") { sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, NULL); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); }
bool FileState::LookupFilesInFolderRecursively(const function<void(const FileItem&)>& visitor, const std::string& folder, int offset /*=0*/, int limit /*=-1*/) { _LOG_DEBUG("LookupFilesInFolderRecursively: [" << folder << "]"); if (limit >= 0) limit++; sqlite3_stmt* stmt; if (folder != "") { /// @todo Do something to improve efficiency of this query. Right now it is basically scanning the whole database sqlite3_prepare_v2(m_db, "SELECT filename,version,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete " " FROM FileState " " WHERE type = 0 AND is_dir_prefix(?, directory)=1 " " ORDER BY filename " " LIMIT ? OFFSET ?", -1, &stmt, 0); // there is a small ambiguity with is_prefix matching, but should be ok for now _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_text(stmt, 1, folder.c_str(), folder.size(), SQLITE_STATIC); _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); sqlite3_bind_int(stmt, 2, limit); sqlite3_bind_int(stmt, 3, offset); } else { sqlite3_prepare_v2(m_db, "SELECT filename,version,device_name,seq_no,file_hash,strftime('%s', file_mtime),file_chmod,file_seg_num,is_complete " " FROM FileState " " WHERE type = 0" " ORDER BY filename " " LIMIT ? OFFSET ?", -1, &stmt, 0); sqlite3_bind_int(stmt, 1, limit); sqlite3_bind_int(stmt, 2, offset); } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); while (sqlite3_step(stmt) == SQLITE_ROW) { if (limit == 1) break; FileItem file; file.set_filename(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 0)); file.set_version(sqlite3_column_int64(stmt, 1)); file.set_device_name(sqlite3_column_blob(stmt, 2), sqlite3_column_bytes(stmt, 2)); file.set_seq_no(sqlite3_column_int64(stmt, 3)); file.set_file_hash(sqlite3_column_blob(stmt, 4), sqlite3_column_bytes(stmt, 4)); file.set_mtime(sqlite3_column_int(stmt, 5)); file.set_mode(sqlite3_column_int(stmt, 6)); file.set_seg_num(sqlite3_column_int64(stmt, 7)); file.set_is_complete(sqlite3_column_int(stmt, 8)); visitor(file); limit--; } _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_DONE, sqlite3_errmsg(m_db)); sqlite3_finalize(stmt); return (limit == 1); }