| // Copyright 2022 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "dlp/dlp_database.h" | |
| #include <cinttypes> | |
| #include <utility> | |
| #include "dlp/dlp_metrics.h" | |
| #include <base/containers/contains.h> | |
| #include <base/files/file_path.h> | |
| #include <base/functional/callback.h> | |
| #include <base/logging.h> | |
| #include <base/strings/strcat.h> | |
| #include <base/strings/string_number_conversions.h> | |
| #include <base/strings/string_util.h> | |
| #include <base/strings/stringprintf.h> | |
| #include <base/task/sequenced_task_runner.h> | |
| #include <sqlite3.h> | |
| namespace dlp { | |
| namespace { | |
| int GetLegacyFileEntriesCallback(void* data, | |
| int count, | |
| char** row, | |
| char** names) { | |
| auto* file_entries_out = static_cast<std::map<FileId, FileEntry>*>(data); | |
| FileEntry file_entry; | |
| if (!row[0]) { | |
| LOG(ERROR) << "FileEntry.inode is null"; | |
| return SQLITE_ERROR; | |
| } | |
| if (!base::StringToUint64(row[0], &file_entry.id.first)) { | |
| LOG(ERROR) << "FileEntry.inode is not a number"; | |
| return SQLITE_ERROR; | |
| } | |
| if (!row[1]) { | |
| LOG(ERROR) << "FileEntry.source_url is null"; | |
| return SQLITE_ERROR; | |
| } | |
| file_entry.source_url = row[1]; | |
| if (!row[2]) { | |
| LOG(ERROR) << "FileEntry.referrer_url is null"; | |
| return SQLITE_ERROR; | |
| } | |
| file_entry.referrer_url = row[2]; | |
| file_entries_out->insert_or_assign(file_entry.id, std::move(file_entry)); | |
| return SQLITE_OK; | |
| } | |
| int GetFileEntriesCallback(void* data, int count, char** row, char** names) { | |
| auto* file_entries_out = static_cast<std::map<FileId, FileEntry>*>(data); | |
| FileEntry file_entry; | |
| if (!row[0]) { | |
| LOG(ERROR) << "FileEntry.inode is null"; | |
| return SQLITE_ERROR; | |
| } | |
| if (!base::StringToUint64(row[0], &file_entry.id.first)) { | |
| LOG(ERROR) << "FileEntry.inode is not a number"; | |
| return SQLITE_ERROR; | |
| } | |
| if (!row[1]) { | |
| LOG(ERROR) << "FileEntry.crtime is null"; | |
| return SQLITE_ERROR; | |
| } | |
| if (!base::StringToInt64(row[1], &file_entry.id.second)) { | |
| LOG(ERROR) << "FileEntry.crtime is not a number"; | |
| return SQLITE_ERROR; | |
| } | |
| if (!row[2]) { | |
| LOG(ERROR) << "FileEntry.source_url is null"; | |
| return SQLITE_ERROR; | |
| } | |
| file_entry.source_url = row[2]; | |
| if (!row[3]) { | |
| LOG(ERROR) << "FileEntry.referrer_url is null"; | |
| return SQLITE_ERROR; | |
| } | |
| file_entry.referrer_url = row[3]; | |
| file_entries_out->insert_or_assign(file_entry.id, std::move(file_entry)); | |
| return SQLITE_OK; | |
| } | |
| int GetIdsCallback(void* data, int count, char** row, char** names) { | |
| auto* ids_out = static_cast<std::set<FileId>*>(data); | |
| if (!row[0] || !row[1]) { | |
| LOG(ERROR) << "file_entries.id is null"; | |
| return SQLITE_ERROR; | |
| } | |
| FileId id; | |
| if (!base::StringToUint64(row[0], &id.first) || | |
| !base::StringToInt64(row[1], &id.second)) { | |
| LOG(ERROR) << "file_entries.id is not a number"; | |
| return SQLITE_ERROR; | |
| } | |
| ids_out->insert(id); | |
| return SQLITE_OK; | |
| } | |
| // Escapes string in SQL. Replaces ' with ''. | |
| std::string EscapeSQLString(const std::string& string_to_escape) { | |
| std::string escaped_string = string_to_escape; | |
| base::ReplaceSubstringsAfterOffset(&escaped_string, 0, "'", "''"); | |
| return escaped_string; | |
| } | |
| } // namespace | |
| class DlpDatabase::Core { | |
| public: | |
| // Creates an instance to talk to the database file at |db_path|. Init() must | |
| // be called to establish connection. | |
| Core(const base::FilePath& db_path, | |
| scoped_refptr<base::SequencedTaskRunner> parent_task_runner, | |
| DlpDatabaseDelegate* const delegate); | |
| // Not copyable or movable. | |
| Core(const Core&) = delete; | |
| Core& operator=(const Core&) = delete; | |
| ~Core(); | |
| // Implements the functionality from main class. | |
| std::pair<int, bool> Init(); | |
| bool UpsertFileEntry(const FileEntry& file_entry); | |
| bool UpsertLegacyFileEntryForTesting(const FileEntry& file_entry); | |
| bool UpsertFileEntries(const std::vector<FileEntry>& file_entries); | |
| std::map<FileId, FileEntry> GetFileEntriesByIds( | |
| std::vector<FileId> ids) const; | |
| std::map<FileId, FileEntry> GetAllEntries() const; | |
| bool DeleteFileEntryByInode(ino64_t inode); | |
| bool DeleteFileEntriesWithIdsNotInSet(std::set<FileId> ids_to_keep); | |
| bool MigrateDatabase(const std::vector<FileId>& existing_files); | |
| private: | |
| // Returns true if the database connection is open. | |
| bool IsOpen() const; | |
| // Closes database connection. Returns |SQLITE_OK| if no error occurred. | |
| // Otherwise SQLite error code is returned. | |
| int Close(); | |
| // Returns true if file entries table exists. | |
| bool FileEntriesTableExists() const; | |
| bool FileEntriesLegacyTableExists() const; | |
| // Creates new file entries table. Returns true if no error occurred. | |
| bool CreateFileEntriesTable(); | |
| bool CreateFileEntriesLegacyTableForTesting(); | |
| using SqliteCallback = int (*)(void*, int, char**, char**); | |
| // Struct holding the result of a call to Sqlite. | |
| struct ExecResult { | |
| int code; | |
| std::string error_msg; | |
| }; | |
| // Execute SQL. | |
| ExecResult ExecSQL(const std::string& sql) const; | |
| ExecResult ExecSQL(const std::string& sql, | |
| SqliteCallback callback, | |
| void* data) const; | |
| // Executes SQL that deletes rows. Returns number of rows affected. Returns -1 | |
| // if error occurs. | |
| int ExecDeleteSQL(const std::string& sql); | |
| void ForwardUMAErrorToParentThread(DatabaseError error) const; | |
| const base::FilePath db_path_; | |
| std::unique_ptr<sqlite3, decltype(&sqlite3_close)> db_; | |
| // Task runner from which this thread is started and where the delegate is | |
| // running. | |
| scoped_refptr<base::SequencedTaskRunner> parent_task_runner_; | |
| DlpDatabaseDelegate* const delegate_; | |
| }; | |
| DlpDatabase::Core::Core( | |
| const base::FilePath& db_path, | |
| scoped_refptr<base::SequencedTaskRunner> parent_task_runner, | |
| DlpDatabaseDelegate* const delegate) | |
| : db_path_(db_path), | |
| db_(nullptr, nullptr), | |
| parent_task_runner_(parent_task_runner), | |
| delegate_(delegate) { | |
| CHECK(delegate_); | |
| CHECK(parent_task_runner_->RunsTasksInCurrentSequence()); | |
| } | |
| DlpDatabase::Core::~Core() { | |
| Close(); | |
| } | |
| std::pair<int, bool> DlpDatabase::Core::Init() { | |
| sqlite3* db_ptr; | |
| int result = sqlite3_open(db_path_.MaybeAsASCII().c_str(), &db_ptr); | |
| db_ = std::unique_ptr<sqlite3, decltype(&sqlite3_close)>(db_ptr, | |
| &sqlite3_close); | |
| if (result != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to connect to database: " << result; | |
| ForwardUMAErrorToParentThread(DatabaseError::kConnectionError); | |
| db_ = nullptr; | |
| } | |
| if (!FileEntriesTableExists() && !CreateFileEntriesTable()) { | |
| LOG(ERROR) << "Failed to create file_entries table"; | |
| ForwardUMAErrorToParentThread(DatabaseError::kCreateTableError); | |
| db_ = nullptr; | |
| } | |
| return {result, /*migration_needed=*/result == SQLITE_OK && | |
| FileEntriesLegacyTableExists()}; | |
| } | |
| bool DlpDatabase::Core::IsOpen() const { | |
| return db_.get() != nullptr; | |
| } | |
| int DlpDatabase::Core::Close() { | |
| if (!db_) | |
| return SQLITE_OK; | |
| int result = sqlite3_close(db_.get()); | |
| if (result == SQLITE_OK) | |
| db_.release(); | |
| return result; | |
| } | |
| bool DlpDatabase::Core::FileEntriesTableExists() const { | |
| const ExecResult result = | |
| ExecSQL("SELECT id FROM file_entries_crtime LIMIT 1"); | |
| return result.error_msg.find("no such table") == std::string::npos; | |
| } | |
| bool DlpDatabase::Core::FileEntriesLegacyTableExists() const { | |
| const ExecResult result = ExecSQL("SELECT id FROM file_entries LIMIT 1"); | |
| return result.error_msg.find("no such table") == std::string::npos; | |
| } | |
| bool DlpDatabase::Core::CreateFileEntriesTable() { | |
| const std::string sql = | |
| "CREATE TABLE file_entries_crtime (" | |
| " inode INTEGER NOT NULL," | |
| " crtime INTEGER NOT NULL," | |
| " source_url TEXT NOT NULL," | |
| " referrer_url TEXT NOT NULL," | |
| "PRIMARY KEY(inode, crtime))"; | |
| const ExecResult result = ExecSQL(sql); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to create table: " << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kCreateTableError); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool DlpDatabase::Core::CreateFileEntriesLegacyTableForTesting() { | |
| const std::string sql = | |
| "CREATE TABLE file_entries (" | |
| " inode INTEGER PRIMARY KEY NOT NULL," | |
| " source_url TEXT NOT NULL," | |
| " referrer_url TEXT NOT NULL" | |
| ")"; | |
| const ExecResult result = ExecSQL(sql); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to create table: " << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kCreateTableError); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool DlpDatabase::Core::UpsertFileEntry(const FileEntry& file_entry) { | |
| if (!IsOpen()) | |
| return false; | |
| const std::string sql = base::StringPrintf( | |
| "INSERT OR REPLACE INTO file_entries_crtime (inode, crtime, source_url, " | |
| "referrer_url)" | |
| " VALUES (%" PRId64 ", %" PRId64 ", '%s', '%s')", | |
| file_entry.id.first, file_entry.id.second, | |
| EscapeSQLString(file_entry.source_url).c_str(), | |
| EscapeSQLString(file_entry.referrer_url).c_str()); | |
| ExecResult result = ExecSQL(sql); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to insert file entry: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kInsertIntoTableError); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool DlpDatabase::Core::UpsertLegacyFileEntryForTesting( | |
| const FileEntry& file_entry) { | |
| if (!IsOpen() || !CreateFileEntriesLegacyTableForTesting()) | |
| return false; | |
| const std::string sql = base::StringPrintf( | |
| "INSERT OR REPLACE INTO file_entries (inode, source_url, referrer_url)" | |
| " VALUES (%" PRId64 ", '%s', '%s')", | |
| file_entry.id.first, EscapeSQLString(file_entry.source_url).c_str(), | |
| EscapeSQLString(file_entry.referrer_url).c_str()); | |
| ExecResult result = ExecSQL(sql); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to insert file entry: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kInsertIntoTableError); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool DlpDatabase::Core::UpsertFileEntries( | |
| const std::vector<FileEntry>& file_entries) { | |
| if (!IsOpen()) { | |
| LOG(ERROR) << "Failed to insert file entries because database is not open"; | |
| return false; | |
| } | |
| std::string sql = | |
| "INSERT OR REPLACE INTO file_entries_crtime (inode, crtime, source_url, " | |
| "referrer_url) " | |
| "VALUES"; | |
| bool first = true; | |
| for (const auto& file_entry : file_entries) { | |
| if (!first) { | |
| sql += ","; | |
| } | |
| sql += base::StringPrintf("(%" PRId64 ", %" PRId64 ", '%s', '%s')", | |
| file_entry.id.first, file_entry.id.second, | |
| EscapeSQLString(file_entry.source_url).c_str(), | |
| EscapeSQLString(file_entry.referrer_url).c_str()); | |
| first = false; | |
| } | |
| sql += ";"; | |
| ExecResult result = ExecSQL(sql); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to insert file entries: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kInsertIntoTableError); | |
| return false; | |
| } | |
| return true; | |
| } | |
| std::map<FileId, FileEntry> DlpDatabase::Core::GetFileEntriesByIds( | |
| std::vector<FileId> ids) const { | |
| std::map<FileId, FileEntry> file_entries; | |
| if (!IsOpen()) | |
| return file_entries; | |
| std::string sql; | |
| sql += | |
| "SELECT inode,crtime,source_url,referrer_url FROM file_entries_crtime " | |
| "WHERE (inode, crtime) IN ("; | |
| bool first = true; | |
| for (FileId id : ids) { | |
| if (!first) { | |
| sql += ","; | |
| } | |
| sql += "(" + base::NumberToString(id.first) + ", " + | |
| base::NumberToString(id.second) + ")"; | |
| first = false; | |
| } | |
| sql += ")"; | |
| ExecResult result = ExecSQL(sql, GetFileEntriesCallback, &file_entries); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to query: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kQueryError); | |
| file_entries.clear(); | |
| return file_entries; | |
| } | |
| return file_entries; | |
| } | |
| std::map<FileId, FileEntry> DlpDatabase::Core::GetAllEntries() const { | |
| std::map<FileId, FileEntry> file_entries; | |
| if (!IsOpen()) | |
| return file_entries; | |
| std::string sql; | |
| sql += "SELECT inode,crtime,source_url,referrer_url FROM file_entries_crtime"; | |
| ExecResult result = ExecSQL(sql, GetFileEntriesCallback, &file_entries); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to query: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kQueryError); | |
| file_entries.clear(); | |
| return file_entries; | |
| } | |
| return file_entries; | |
| } | |
| bool DlpDatabase::Core::DeleteFileEntryByInode(ino64_t inode) { | |
| if (!IsOpen()) | |
| return false; | |
| const std::string sql = base::StringPrintf( | |
| "DELETE FROM file_entries_crtime WHERE inode = %" PRId64, inode); | |
| return ExecDeleteSQL(sql) >= 0; | |
| } | |
| bool DlpDatabase::Core::DeleteFileEntriesWithIdsNotInSet( | |
| std::set<FileId> ids_to_keep) { | |
| if (!IsOpen()) | |
| return false; | |
| std::set<FileId> ids; | |
| ExecResult result = ExecSQL("SELECT inode,crtime FROM file_entries_crtime", | |
| GetIdsCallback, &ids); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to query: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kQueryError); | |
| return false; | |
| } | |
| std::erase_if(ids, [&ids_to_keep](FileId id) { | |
| return base::Contains(ids_to_keep, id); | |
| }); | |
| if (ids.size() == 0) { | |
| return true; | |
| } | |
| std::string sql = | |
| "DELETE FROM file_entries_crtime WHERE (inode, crtime) IN ("; | |
| bool first = true; | |
| for (FileId id : ids) { | |
| if (!first) { | |
| sql += ","; | |
| } | |
| sql += "(" + base::NumberToString(id.first) + ", " + | |
| base::NumberToString(id.second) + ")"; | |
| first = false; | |
| } | |
| sql += ")"; | |
| const int deleted = ExecDeleteSQL(sql); | |
| if (deleted != ids.size()) { | |
| LOG(ERROR) << "Failed to cleanup database, deleted: " << deleted | |
| << ", instead of: " << ids.size(); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool DlpDatabase::Core::MigrateDatabase( | |
| const std::vector<FileId>& existing_files) { | |
| // The old database is already migrated and removed. | |
| if (!IsOpen() || !FileEntriesLegacyTableExists()) { | |
| return true; | |
| } | |
| std::map<FileId, FileEntry> old_file_entries; | |
| std::string sql = "SELECT inode,source_url,referrer_url FROM file_entries"; | |
| ExecResult result = | |
| ExecSQL(sql, GetLegacyFileEntriesCallback, &old_file_entries); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to query: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kQueryError); | |
| return false; | |
| } | |
| LOG(INFO) << "Found " << old_file_entries.size() << " entries to migrate"; | |
| std::map<ino64_t, time_t> inode_to_crtime; | |
| for (const auto& file_id : existing_files) { | |
| inode_to_crtime[file_id.first] = file_id.second; | |
| } | |
| std::vector<FileEntry> entries_to_add; | |
| for (const auto& [old_file_id, old_entry] : old_file_entries) { | |
| auto iter = inode_to_crtime.find(old_file_id.first); | |
| if (iter != inode_to_crtime.end()) { | |
| FileEntry entry; | |
| entry.id = {old_file_id.first, iter->second}; | |
| entry.source_url = old_entry.source_url; | |
| entry.referrer_url = old_entry.referrer_url; | |
| entries_to_add.emplace_back(entry); | |
| } else { | |
| LOG(ERROR) << "Not found file while migrating, inode=" | |
| << old_file_id.first; | |
| } | |
| } | |
| if (entries_to_add.size() > 0 && !UpsertFileEntries(entries_to_add)) { | |
| return false; | |
| } | |
| LOG(INFO) << "Migrated " << entries_to_add.size() << " entries"; | |
| result = ExecSQL("DROP TABLE file_entries"); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to delete legacy table: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kQueryError); | |
| return false; | |
| } | |
| return true; | |
| } | |
| DlpDatabase::Core::ExecResult DlpDatabase::Core::ExecSQL( | |
| const std::string& sql) const { | |
| return ExecSQL(sql, nullptr, nullptr); | |
| } | |
| DlpDatabase::Core::ExecResult DlpDatabase::Core::ExecSQL( | |
| const std::string& sql, SqliteCallback callback, void* data) const { | |
| char* error_msg = nullptr; | |
| int result = sqlite3_exec(db_.get(), sql.c_str(), callback, data, &error_msg); | |
| // According to sqlite3_exec() documentation, error_msg points to memory | |
| // allocated by sqlite3_malloc(), which must be freed by sqlite3_free(). | |
| std::string error_msg_str; | |
| if (error_msg) { | |
| error_msg_str.assign(error_msg); | |
| sqlite3_free(error_msg); | |
| } | |
| return {result, error_msg_str}; | |
| } | |
| int DlpDatabase::Core::ExecDeleteSQL(const std::string& sql) { | |
| ExecResult result = ExecSQL(sql); | |
| if (result.code != SQLITE_OK) { | |
| LOG(ERROR) << "Failed to delete: (" << result.code << ") " | |
| << result.error_msg; | |
| ForwardUMAErrorToParentThread(DatabaseError::kDeleteError); | |
| return -1; | |
| } | |
| return sqlite3_changes(db_.get()); | |
| } | |
| void DlpDatabase::Core::ForwardUMAErrorToParentThread( | |
| DatabaseError error) const { | |
| parent_task_runner_->PostTask( | |
| FROM_HERE, base::BindOnce(&DlpDatabaseDelegate::OnDatabaseError, | |
| base::Unretained(delegate_), error)); | |
| } | |
| DlpDatabase::DlpDatabase(const base::FilePath& db_path, Delegate* delegate) | |
| : database_thread_("dlp_database_thread"), delegate_(delegate) { | |
| DCHECK(delegate); | |
| CHECK(database_thread_.Start()) << "Failed to start database thread."; | |
| task_runner_ = database_thread_.task_runner(); | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| core_ = std::make_unique<Core>( | |
| db_path, base::SequencedTaskRunner::GetCurrentDefault(), this); | |
| } | |
| DlpDatabase::~DlpDatabase() { | |
| core_.reset(); | |
| database_thread_.Stop(); | |
| } | |
| void DlpDatabase::Init( | |
| base::OnceCallback<void(std::pair<int, bool>)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::Init, base::Unretained(core_.get())), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::UpsertFileEntry(const FileEntry& file_entry, | |
| base::OnceCallback<void(bool)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::UpsertFileEntry, | |
| base::Unretained(core_.get()), file_entry), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::UpsertLegacyFileEntryForTesting( | |
| const FileEntry& file_entry, base::OnceCallback<void(bool)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::UpsertLegacyFileEntryForTesting, | |
| base::Unretained(core_.get()), file_entry), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::UpsertFileEntries(const std::vector<FileEntry>& file_entries, | |
| base::OnceCallback<void(bool)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::UpsertFileEntries, | |
| base::Unretained(core_.get()), file_entries), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::GetFileEntriesByIds( | |
| std::vector<FileId> ids, | |
| base::OnceCallback<void(std::map<FileId, FileEntry>)> callback) const { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::GetFileEntriesByIds, | |
| base::Unretained(core_.get()), std::move(ids)), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::GetDatabaseEntries( | |
| base::OnceCallback<void(std::map<FileId, FileEntry>)> callback) const { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::GetAllEntries, | |
| base::Unretained(core_.get())), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::DeleteFileEntryByInode( | |
| ino64_t inode, base::OnceCallback<void(bool)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::DeleteFileEntryByInode, | |
| base::Unretained(core_.get()), inode), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::DeleteFileEntriesWithIdsNotInSet( | |
| std::set<FileId> ids_to_keep, base::OnceCallback<void(bool)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::DeleteFileEntriesWithIdsNotInSet, | |
| base::Unretained(core_.get()), ids_to_keep), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::MigrateDatabase(const std::vector<FileId>& existing_files, | |
| base::OnceCallback<void(bool)> callback) { | |
| CHECK(!task_runner_->RunsTasksInCurrentSequence()); | |
| task_runner_->PostTaskAndReplyWithResult( | |
| FROM_HERE, | |
| base::BindOnce(&DlpDatabase::Core::MigrateDatabase, | |
| base::Unretained(core_.get()), existing_files), | |
| std::move(callback)); | |
| } | |
| void DlpDatabase::OnDatabaseError(DatabaseError error) { | |
| delegate_->OnDatabaseError(error); | |
| } | |
| } // namespace dlp |