| 117 | } |
| 118 | |
| 119 | bool IsSQLiteFile(const fs::path& path) |
| 120 | { |
| 121 | if (!fs::exists(path)) return false; |
| 122 | |
| 123 | // A SQLite Database file is at least 512 bytes. |
| 124 | std::error_code ec; |
| 125 | auto size = fs::file_size(path, ec); |
| 126 | if (ec) LogWarning("Error reading file_size: %s [%s]", ec.message(), fs::PathToString(path)); |
| 127 | if (size < 512) return false; |
| 128 | |
| 129 | std::ifstream file{path.std_path(), std::ios::binary}; |
| 130 | if (!file.is_open()) return false; |
| 131 | |
| 132 | // Magic is at beginning and is 16 bytes long |
| 133 | char magic[16]; |
| 134 | file.read(magic, 16); |
| 135 | |
| 136 | // Application id is at offset 68 and 4 bytes long |
| 137 | file.seekg(68, std::ios::beg); |
| 138 | char app_id[4]; |
| 139 | file.read(app_id, 4); |
| 140 | |
| 141 | file.close(); |
| 142 | |
| 143 | // Check the magic, see https://sqlite.org/fileformat.html |
| 144 | std::string magic_str(magic, 16); |
| 145 | if (magic_str != std::string{"SQLite format 3\000", 16}) { |
| 146 | return false; |
| 147 | } |
| 148 | |
| 149 | // Check the application id matches our network magic |
| 150 | return memcmp(Params().MessageStart().data(), app_id, 4) == 0; |
| 151 | } |
| 152 | |
| 153 | void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options) |
| 154 | { |