Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| 2 | /** |
| 3 | * Copyright (c) 2013-2016, Regents of the University of California. |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 4 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 5 | * This file is part of ChronoShare, a decentralized file sharing application over NDN. |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 6 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 7 | * ChronoShare is free software: you can redistribute it and/or modify it under the terms |
| 8 | * of the GNU General Public License as published by the Free Software Foundation, either |
| 9 | * version 3 of the License, or (at your option) any later version. |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 10 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 11 | * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY |
| 12 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
| 13 | * PARTICULAR PURPOSE. See the GNU General Public License for more details. |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 14 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 15 | * You should have received copies of the GNU General Public License along with |
| 16 | * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. |
| 17 | * |
| 18 | * See AUTHORS.md for complete list of ChronoShare authors and contributors. |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 19 | */ |
| 20 | |
Alexander Afanasyev | 242f877 | 2013-01-01 23:26:31 -0800 | [diff] [blame] | 21 | #include "db-helper.h" |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 22 | #include "logging.h" |
| 23 | |
Alexander Afanasyev | ae43c50 | 2012-12-29 17:26:37 -0800 | [diff] [blame] | 24 | #include <boost/make_shared.hpp> |
| 25 | #include <boost/ref.hpp> |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 26 | #include <boost/throw_exception.hpp> |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 27 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 28 | INIT_LOGGER("DbHelper"); |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 29 | |
Alexander Afanasyev | ae43c50 | 2012-12-29 17:26:37 -0800 | [diff] [blame] | 30 | using namespace boost; |
Alexander Afanasyev | 68f2a95 | 2013-01-08 14:34:16 -0800 | [diff] [blame] | 31 | namespace fs = boost::filesystem; |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 32 | |
| 33 | const std::string INIT_DATABASE = "\ |
Alexander Afanasyev | 0995f32 | 2013-01-22 13:16:46 -0800 | [diff] [blame] | 34 | PRAGMA foreign_keys = ON; \ |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 35 | "; |
| 36 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 37 | DbHelper::DbHelper(const fs::path& path, const std::string& dbname) |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 38 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 39 | fs::create_directories(path); |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 40 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 41 | int res = sqlite3_open((path / dbname).c_str(), &m_db); |
| 42 | if (res != SQLITE_OK) { |
| 43 | BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot open/create dabatabase: [" + |
| 44 | (path / dbname).string() + "]")); |
| 45 | } |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 46 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 47 | res = sqlite3_create_function(m_db, "hash", 2, SQLITE_ANY, 0, 0, DbHelper::hash_xStep, |
| 48 | DbHelper::hash_xFinal); |
| 49 | if (res != SQLITE_OK) { |
| 50 | BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot create function ``hash''")); |
| 51 | } |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 52 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 53 | res = sqlite3_create_function(m_db, "is_prefix", 2, SQLITE_ANY, 0, DbHelper::is_prefix_xFun, 0, 0); |
| 54 | if (res != SQLITE_OK) { |
| 55 | BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot create function ``is_prefix''")); |
| 56 | } |
Alexander Afanasyev | 026eaf3 | 2013-02-23 16:37:14 -0800 | [diff] [blame] | 57 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 58 | res = sqlite3_create_function(m_db, "directory_name", -1, SQLITE_ANY, 0, |
| 59 | DbHelper::directory_name_xFun, 0, 0); |
| 60 | if (res != SQLITE_OK) { |
| 61 | BOOST_THROW_EXCEPTION(Error::Db() |
| 62 | << errmsg_info_str("Cannot create function ``directory_name''")); |
| 63 | } |
Alexander Afanasyev | 95f9f55 | 2013-02-26 23:05:20 -0800 | [diff] [blame] | 64 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 65 | res = sqlite3_create_function(m_db, "is_dir_prefix", 2, SQLITE_ANY, 0, |
| 66 | DbHelper::is_dir_prefix_xFun, 0, 0); |
| 67 | if (res != SQLITE_OK) { |
| 68 | BOOST_THROW_EXCEPTION(Error::Db() << errmsg_info_str("Cannot create function ``is_dir_prefix''")); |
| 69 | } |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 70 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 71 | sqlite3_exec(m_db, INIT_DATABASE.c_str(), NULL, NULL, NULL); |
| 72 | _LOG_DEBUG_COND(sqlite3_errcode(m_db) != SQLITE_OK, sqlite3_errmsg(m_db)); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 73 | } |
| 74 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 75 | DbHelper::~DbHelper() |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 76 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 77 | int res = sqlite3_close(m_db); |
| 78 | if (res != SQLITE_OK) { |
| 79 | // complain |
| 80 | } |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 81 | } |
| 82 | |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 83 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 84 | DbHelper::hash_xStep(sqlite3_context* context, int argc, sqlite3_value** argv) |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 85 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 86 | if (argc != 2) { |
| 87 | // _LOG_ERROR ("Wrong arguments are supplied for ``hash'' function"); |
| 88 | sqlite3_result_error(context, "Wrong arguments are supplied for ``hash'' function", -1); |
| 89 | return; |
| 90 | } |
| 91 | if (sqlite3_value_type(argv[0]) != SQLITE_BLOB || sqlite3_value_type(argv[1]) != SQLITE_INTEGER) { |
| 92 | // _LOG_ERROR ("Hash expects (blob,integer) parameters"); |
| 93 | sqlite3_result_error(context, "Hash expects (blob,integer) parameters", -1); |
| 94 | return; |
| 95 | } |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 96 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 97 | EVP_MD_CTX** hash_context = |
| 98 | reinterpret_cast<EVP_MD_CTX**>(sqlite3_aggregate_context(context, sizeof(EVP_MD_CTX*))); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 99 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 100 | if (hash_context == 0) { |
| 101 | sqlite3_result_error_nomem(context); |
| 102 | return; |
| 103 | } |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 104 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 105 | if (*hash_context == 0) { |
| 106 | *hash_context = EVP_MD_CTX_create(); |
| 107 | EVP_DigestInit_ex(*hash_context, HASH_FUNCTION(), 0); |
| 108 | } |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 109 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 110 | int nameBytes = sqlite3_value_bytes(argv[0]); |
| 111 | const void* name = sqlite3_value_blob(argv[0]); |
| 112 | sqlite3_int64 seqno = sqlite3_value_int64(argv[1]); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 113 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 114 | EVP_DigestUpdate(*hash_context, name, nameBytes); |
| 115 | EVP_DigestUpdate(*hash_context, &seqno, sizeof(sqlite3_int64)); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 119 | DbHelper::hash_xFinal(sqlite3_context* context) |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 120 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 121 | EVP_MD_CTX** hash_context = |
| 122 | reinterpret_cast<EVP_MD_CTX**>(sqlite3_aggregate_context(context, sizeof(EVP_MD_CTX*))); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 123 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 124 | if (hash_context == 0) { |
| 125 | sqlite3_result_error_nomem(context); |
| 126 | return; |
| 127 | } |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 128 | |
| 129 | if (*hash_context == 0) // no rows |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 130 | { |
| 131 | char charNullResult = 0; |
| 132 | sqlite3_result_blob(context, &charNullResult, 1, |
| 133 | SQLITE_TRANSIENT); //SQLITE_TRANSIENT forces to make a copy |
| 134 | return; |
| 135 | } |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 136 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 137 | unsigned char* hash = new unsigned char[EVP_MAX_MD_SIZE]; |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 138 | unsigned int hashLength = 0; |
| 139 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 140 | int ok = EVP_DigestFinal_ex(*hash_context, hash, &hashLength); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 141 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 142 | sqlite3_result_blob(context, hash, hashLength, |
| 143 | SQLITE_TRANSIENT); //SQLITE_TRANSIENT forces to make a copy |
| 144 | delete[] hash; |
Alexander Afanasyev | 8e2104a | 2013-01-22 10:56:18 -0800 | [diff] [blame] | 145 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 146 | EVP_MD_CTX_destroy(*hash_context); |
Alexander Afanasyev | 71b43e7 | 2012-12-27 01:03:43 -0800 | [diff] [blame] | 147 | } |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 148 | |
Alexander Afanasyev | 026eaf3 | 2013-02-23 16:37:14 -0800 | [diff] [blame] | 149 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 150 | DbHelper::is_prefix_xFun(sqlite3_context* context, int argc, sqlite3_value** argv) |
Alexander Afanasyev | 026eaf3 | 2013-02-23 16:37:14 -0800 | [diff] [blame] | 151 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 152 | int len1 = sqlite3_value_bytes(argv[0]); |
| 153 | int len2 = sqlite3_value_bytes(argv[1]); |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 154 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 155 | if (len1 == 0) { |
| 156 | sqlite3_result_int(context, 1); |
| 157 | return; |
| 158 | } |
Alexander Afanasyev | 026eaf3 | 2013-02-23 16:37:14 -0800 | [diff] [blame] | 159 | |
| 160 | if (len1 > len2) // first parameter should be at most equal in length to the second one |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 161 | { |
| 162 | sqlite3_result_int(context, 0); |
| 163 | return; |
| 164 | } |
Alexander Afanasyev | 026eaf3 | 2013-02-23 16:37:14 -0800 | [diff] [blame] | 165 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 166 | if (memcmp(sqlite3_value_blob(argv[0]), sqlite3_value_blob(argv[1]), len1) == 0) { |
| 167 | sqlite3_result_int(context, 1); |
| 168 | } |
| 169 | else { |
| 170 | sqlite3_result_int(context, 0); |
| 171 | } |
Alexander Afanasyev | 026eaf3 | 2013-02-23 16:37:14 -0800 | [diff] [blame] | 172 | } |
Alexander Afanasyev | ae43c50 | 2012-12-29 17:26:37 -0800 | [diff] [blame] | 173 | |
Alexander Afanasyev | 95f9f55 | 2013-02-26 23:05:20 -0800 | [diff] [blame] | 174 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 175 | DbHelper::directory_name_xFun(sqlite3_context* context, int argc, sqlite3_value** argv) |
Alexander Afanasyev | 95f9f55 | 2013-02-26 23:05:20 -0800 | [diff] [blame] | 176 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 177 | if (argc != 1) { |
| 178 | sqlite3_result_error(context, "``directory_name'' expects 1 text argument", -1); |
| 179 | sqlite3_result_null(context); |
| 180 | return; |
| 181 | } |
Alexander Afanasyev | 95f9f55 | 2013-02-26 23:05:20 -0800 | [diff] [blame] | 182 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 183 | if (sqlite3_value_bytes(argv[0]) == 0) { |
| 184 | sqlite3_result_null(context); |
| 185 | return; |
| 186 | } |
Alexander Afanasyev | 95f9f55 | 2013-02-26 23:05:20 -0800 | [diff] [blame] | 187 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 188 | boost::filesystem::path filePath( |
| 189 | std::string(reinterpret_cast<const char*>(sqlite3_value_text(argv[0])), |
| 190 | sqlite3_value_bytes(argv[0]))); |
| 191 | std::string dirPath = filePath.parent_path().generic_string(); |
| 192 | // _LOG_DEBUG("directory_name FUN: " << dirPath); |
| 193 | if (dirPath.size() == 0) { |
| 194 | sqlite3_result_null(context); |
| 195 | } |
| 196 | else { |
| 197 | sqlite3_result_text(context, dirPath.c_str(), dirPath.size(), SQLITE_TRANSIENT); |
| 198 | } |
Alexander Afanasyev | 95f9f55 | 2013-02-26 23:05:20 -0800 | [diff] [blame] | 199 | } |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 200 | |
| 201 | void |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 202 | DbHelper::is_dir_prefix_xFun(sqlite3_context* context, int argc, sqlite3_value** argv) |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 203 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 204 | int len1 = sqlite3_value_bytes(argv[0]); |
| 205 | int len2 = sqlite3_value_bytes(argv[1]); |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 206 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 207 | if (len1 == 0) { |
| 208 | sqlite3_result_int(context, 1); |
| 209 | return; |
| 210 | } |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 211 | |
| 212 | if (len1 > len2) // first parameter should be at most equal in length to the second one |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 213 | { |
| 214 | sqlite3_result_int(context, 0); |
| 215 | return; |
| 216 | } |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 217 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 218 | if (memcmp(sqlite3_value_blob(argv[0]), sqlite3_value_blob(argv[1]), len1) == 0) { |
| 219 | if (len1 == len2) { |
| 220 | sqlite3_result_int(context, 1); |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 221 | } |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 222 | else { |
| 223 | if (reinterpret_cast<const char*>(sqlite3_value_blob(argv[1]))[len1] == '/') { |
| 224 | sqlite3_result_int(context, 1); |
| 225 | } |
| 226 | else { |
| 227 | sqlite3_result_int(context, 0); |
| 228 | } |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 229 | } |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 230 | } |
| 231 | else { |
| 232 | sqlite3_result_int(context, 0); |
| 233 | } |
Alexander Afanasyev | 20fd84a | 2013-02-27 12:17:00 -0800 | [diff] [blame] | 234 | } |