diff options
Diffstat (limited to 'src/db.cpp')
| -rw-r--r-- | src/db.cpp | 91 |
1 files changed, 89 insertions, 2 deletions
| @@ -101,10 +101,13 @@ bool WalletSQLiteRuntimeActive() | |||
| 101 | return pWalletSQLiteRuntime != NULL; | 101 | return pWalletSQLiteRuntime != NULL; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet) | 104 | bool WalletSQLiteRuntimeOpen(const string& strPath, string& strErrorRet, bool fMustExist) |
| 105 | { | 105 | { |
| 106 | strErrorRet.clear(); | 106 | strErrorRet.clear(); |
| 107 | if (!FileExists(strPath.c_str())) | 107 | // Callers that load an existing wallet want the clear "does not exist" |
| 108 | // message rather than silently creating a blank one; the create path passes | ||
| 109 | // fMustExist=false so Open() (SQLITE_OPEN_CREATE) can make a fresh file. | ||
| 110 | if (fMustExist && !FileExists(strPath.c_str())) | ||
| 108 | { | 111 | { |
| 109 | strErrorRet = strprintf("SQLite wallet does not exist: %s", | 112 | strErrorRet = strprintf("SQLite wallet does not exist: %s", |
| 110 | strPath.c_str()); | 113 | strPath.c_str()); |
| @@ -230,6 +233,47 @@ bool WalletSQLiteRuntimeCheckpoint(string& strErrorRet) | |||
| 230 | return pWalletSQLiteRuntime->Checkpoint(strErrorRet); | 233 | return pWalletSQLiteRuntime->Checkpoint(strErrorRet); |
| 231 | } | 234 | } |
| 232 | 235 | ||
| 236 | // The persistent record of which backend this datadir uses, so the choice | ||
| 237 | // survives a restart without a command-line flag. A plain text file holding | ||
| 238 | // "sqlite" or "bdb" -- visible and hand-editable on purpose, no hidden state. | ||
| 239 | static string WalletBackendMarkerPath() | ||
| 240 | { | ||
| 241 | return GetAppDir() + "/wallet-backend"; | ||
| 242 | } | ||
| 243 | |||
| 244 | string ReadWalletBackendMarker() | ||
| 245 | { | ||
| 246 | FILE* pf = fopen(WalletBackendMarkerPath().c_str(), "rb"); | ||
| 247 | if (!pf) | ||
| 248 | return ""; | ||
| 249 | char buf[16] = {0}; | ||
| 250 | size_t n = fread(buf, 1, sizeof(buf) - 1, pf); | ||
| 251 | fclose(pf); | ||
| 252 | string s(buf, n); | ||
| 253 | while (!s.empty() && isspace((unsigned char)s[s.size() - 1])) | ||
| 254 | s.erase(s.size() - 1); | ||
| 255 | while (!s.empty() && isspace((unsigned char)s[0])) | ||
| 256 | s.erase(0, 1); | ||
| 257 | if (s == "sqlite" || s == "bdb") | ||
| 258 | return s; | ||
| 259 | return ""; | ||
| 260 | } | ||
| 261 | |||
| 262 | bool WriteWalletBackendMarker(const string& strBackend) | ||
| 263 | { | ||
| 264 | if (strBackend != "sqlite" && strBackend != "bdb") | ||
| 265 | return false; | ||
| 266 | FILE* pf = fopen(WalletBackendMarkerPath().c_str(), "wb"); | ||
| 267 | if (!pf) | ||
| 268 | return false; | ||
| 269 | bool fOk = fwrite(strBackend.c_str(), 1, strBackend.size(), pf) == strBackend.size(); | ||
| 270 | if (fputc('\n', pf) == EOF) | ||
| 271 | fOk = false; | ||
| 272 | if (fclose(pf) != 0) | ||
| 273 | fOk = false; | ||
| 274 | return fOk; | ||
| 275 | } | ||
| 276 | |||
| 233 | 277 | ||
| 234 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) | 278 | CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) |
| 235 | { | 279 | { |
| @@ -1609,6 +1653,49 @@ bool LoadWalletFromSQLiteRuntime(const string& strPath) | |||
| 1609 | return true; | 1653 | return true; |
| 1610 | } | 1654 | } |
| 1611 | 1655 | ||
| 1656 | // Create a brand-new wallet directly in the SQLite backend. For a fresh install | ||
| 1657 | // where SQLite is the default there is no wallet.dat to export from, so open a | ||
| 1658 | // new wallet.sqlite (Open() creates the file and its schema) and let | ||
| 1659 | // FinishLoadedWallet mint the first default key straight into it -- the same | ||
| 1660 | // call the Berkeley DB create path uses, so a new wallet is identical either | ||
| 1661 | // way. Refuses to touch an existing file, and cleans up on failure so a broken | ||
| 1662 | // half-initialised wallet.sqlite is never left for the next start to load. | ||
| 1663 | bool CreateNewSQLiteWallet(const string& strPath) | ||
| 1664 | { | ||
| 1665 | strWalletLoadError.clear(); | ||
| 1666 | |||
| 1667 | if (FileExists(strPath.c_str())) | ||
| 1668 | { | ||
| 1669 | strWalletLoadError = strprintf("SQLite wallet already exists: %s", | ||
| 1670 | strPath.c_str()); | ||
| 1671 | printf("CreateNewSQLiteWallet: %s\n", strWalletLoadError.c_str()); | ||
| 1672 | return false; | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | string strError; | ||
| 1676 | if (!WalletSQLiteRuntimeOpen(strPath, strError, false)) | ||
| 1677 | { | ||
| 1678 | strWalletLoadError = strError; | ||
| 1679 | printf("CreateNewSQLiteWallet: cannot create SQLite wallet: %s\n", | ||
| 1680 | strError.c_str()); | ||
| 1681 | return false; | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | vector<unsigned char> vchNoDefaultKey; | ||
| 1685 | if (!FinishLoadedWallet(vchNoDefaultKey, true)) | ||
| 1686 | { | ||
| 1687 | WalletSQLiteRuntimeClose(); | ||
| 1688 | remove(strPath.c_str()); | ||
| 1689 | remove((strPath + "-wal").c_str()); | ||
| 1690 | remove((strPath + "-shm").c_str()); | ||
| 1691 | if (strWalletLoadError.empty()) | ||
| 1692 | strWalletLoadError = "could not initialise the new SQLite wallet"; | ||
| 1693 | return false; | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | return true; | ||
| 1697 | } | ||
| 1698 | |||
| 1612 | 1699 | ||
| 1613 | // Write a copy of wallet.dat that can be opened anywhere. | 1700 | // Write a copy of wallet.dat that can be opened anywhere. |
| 1614 | // | 1701 | // |