From ed3d8bba1b542e0bbf382a6f2eb4b78147d10bc0 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 10 Jan 2015 12:39:54 +0000 Subject: - writeable module names; - compilation fix for 32 bits build; - DatabaseCorruption() returned git-svn-id: http://svn.miranda-ng.org/main/trunk@11812 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Dbx_mdb/src/dbcontacts.cpp | 51 ++++++++++++-------------- plugins/Dbx_mdb/src/dbintf.cpp | 61 +++++++++++++++++++++++++++---- plugins/Dbx_mdb/src/dbintf.h | 5 ++- plugins/Dbx_mdb/src/dbmodulechain.cpp | 69 ++++++++++++++++++++++++----------- plugins/Dbx_mdb/src/dbsettings.cpp | 15 ++++++++ plugins/Dbx_mdb/src/lmdb/mdb.c | 2 +- 6 files changed, 145 insertions(+), 58 deletions(-) (limited to 'plugins/Dbx_mdb') diff --git a/plugins/Dbx_mdb/src/dbcontacts.cpp b/plugins/Dbx_mdb/src/dbcontacts.cpp index ae960f8696..88a31f58d7 100644 --- a/plugins/Dbx_mdb/src/dbcontacts.cpp +++ b/plugins/Dbx_mdb/src/dbcontacts.cpp @@ -85,30 +85,30 @@ STDMETHODIMP_(LONG) CDbxMdb::DeleteContact(MCONTACT contactID) NotifyEventHooks(hContactDeletedEvent, contactID, 0); // delete - mir_cslock lck(m_csDbAccess); + MDB_val key = { sizeof(DWORD), &contactID }; + MDB_txn *txn; + mdb_txn_begin(m_pMdbEnv, NULL, 0, &txn); + mdb_del(txn, m_dbContacts, &key, NULL); + mdb_txn_commit(txn); return 0; } STDMETHODIMP_(MCONTACT) CDbxMdb::AddContact() { - DWORD dwContactId; - DBContact dbc = { 0 }; + DBContact dbc; dbc.signature = DBCONTACT_SIGNATURE; - { - mir_cslock lck(m_csDbAccess); - - dwContactId = m_dwMaxContactId++; + dbc.eventCount = 0; + + DWORD dwContactId = m_dwMaxContactId++; - MDB_val key, data; - key.mv_size = sizeof(DWORD); key.mv_data = &dwContactId; - data.mv_size = sizeof(DBContact); data.mv_data = &dbc; + MDB_val key = { sizeof(DWORD), &dwContactId }; + MDB_val data = { sizeof(DBContact), &dbc }; - MDB_txn *txn; - mdb_txn_begin(m_pMdbEnv, NULL, 0, &txn); - mdb_put(txn, m_dbContacts, &key, &data, 0); - mdb_txn_commit(txn); - } + MDB_txn *txn; + mdb_txn_begin(m_pMdbEnv, NULL, 0, &txn); + mdb_put(txn, m_dbContacts, &key, &data, 0); + mdb_txn_commit(txn); DBCachedContact *cc = m_cache->AddContactToCache(dwContactId); cc->dwDriverData = 0; @@ -120,17 +120,7 @@ STDMETHODIMP_(MCONTACT) CDbxMdb::AddContact() STDMETHODIMP_(BOOL) CDbxMdb::IsDbContact(MCONTACT contactID) { DBCachedContact *cc = m_cache->GetCachedContact(contactID); - if (cc == NULL) - return FALSE; - - mir_cslock lck(m_csDbAccess); - DBContact *dbc = NULL; - if (dbc->signature == DBCONTACT_SIGNATURE) { - m_cache->AddContactToCache(contactID); - return TRUE; - } - - return FALSE; + return (cc != NULL); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -173,8 +163,11 @@ void CDbxMdb::FillContacts() { m_contactCount = 0; + MDB_txn *txn; + mdb_txn_begin(m_pMdbEnv, NULL, MDB_RDONLY, &txn); + MDB_cursor *cursor; - mdb_cursor_open(m_txn, m_dbModules, &cursor); + mdb_cursor_open(txn, m_dbContacts, &cursor); DWORD dwContactId; DBContact value; @@ -184,6 +177,9 @@ void CDbxMdb::FillContacts() data.mv_size = sizeof(DBContact); data.mv_data = &value; while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == 0) { + if (value.signature != DBCONTACT_SIGNATURE) + DatabaseCorruption(NULL); + DBCachedContact *cc = m_cache->AddContactToCache(dwContactId); cc->dwDriverData = 0; CheckProto(cc, ""); @@ -206,4 +202,5 @@ void CDbxMdb::FillContacts() } mdb_cursor_close(cursor); + mdb_txn_abort(txn); } diff --git a/plugins/Dbx_mdb/src/dbintf.cpp b/plugins/Dbx_mdb/src/dbintf.cpp index 880c0c80fd..43a15b6457 100644 --- a/plugins/Dbx_mdb/src/dbintf.cpp +++ b/plugins/Dbx_mdb/src/dbintf.cpp @@ -95,11 +95,11 @@ int CDbxMdb::Load(bool bSkipInit) return EGROKPRF_CANTREAD; if (!bSkipInit) { - mdb_txn_begin(m_pMdbEnv, NULL, 0, &m_txn); - - mdb_open(m_txn, "modules", MDB_CREATE | MDB_INTEGERKEY, &m_dbModules); - mdb_open(m_txn, "contacts", MDB_CREATE | MDB_INTEGERKEY, &m_dbContacts); - mdb_open(m_txn, "events", MDB_CREATE | MDB_INTEGERKEY, &m_dbEvents); + MDB_txn *txn; + mdb_txn_begin(m_pMdbEnv, NULL, 0, &txn); + mdb_open(txn, "contacts", MDB_CREATE | MDB_INTEGERKEY, &m_dbContacts); + mdb_open(txn, "events", MDB_CREATE | MDB_INTEGERKEY, &m_dbEvents); + mdb_txn_commit(txn); if (InitModuleNames()) return EGROKPRF_CANTREAD; if (InitCrypt()) return EGROKPRF_CANTREAD; @@ -156,7 +156,7 @@ int CDbxMdb::Check(void) return (memcmp(buf + 16, "\xDE\xC0\xEF\xBE", 4)) ? EGROKPRF_UNKHEADER : 0; } -int CDbxMdb::PrepareCheck(int *error) +int CDbxMdb::PrepareCheck(int*) { InitModuleNames(); return InitCrypt(); @@ -168,6 +168,53 @@ STDMETHODIMP_(void) CDbxMdb::SetCacheSafetyMode(BOOL bIsSet) m_safetyMode = bIsSet != 0; } +///////////////////////////////////////////////////////////////////////////////////////// + +static DWORD DatabaseCorrupted = 0; +static const TCHAR *msg = NULL; +static DWORD dwErr = 0; +static TCHAR tszPanic[] = LPGENT("Miranda has detected corruption in your database. This corruption may be fixed by DbChecker plugin. Please download it from http://miranda-ng.org/p/DbChecker/. Miranda will now shut down."); + +void __cdecl dbpanic(void *) +{ + if (msg) { + if (dwErr == ERROR_DISK_FULL) + msg = TranslateT("Disk is full. Miranda will now shut down."); + + TCHAR err[256]; + mir_sntprintf(err, SIZEOF(err), msg, TranslateT("Database failure. Miranda will now shut down."), dwErr); + + MessageBox(0, err, TranslateT("Database Error"), MB_SETFOREGROUND | MB_TOPMOST | MB_APPLMODAL | MB_ICONWARNING | MB_OK); + } + else MessageBox(0, TranslateTS(tszPanic), TranslateT("Database Panic"), MB_SETFOREGROUND | MB_TOPMOST | MB_APPLMODAL | MB_ICONWARNING | MB_OK); + TerminateProcess(GetCurrentProcess(), 255); +} + +void CDbxMdb::DatabaseCorruption(const TCHAR *text) +{ + int kill = 0; + + mir_cslockfull lck(m_csDbAccess); + if (DatabaseCorrupted == 0) { + DatabaseCorrupted++; + kill++; + msg = text; + dwErr = GetLastError(); + } + else { + /* db is already corrupted, someone else is dealing with it, wait here + so that we don't do any more damage */ + Sleep(INFINITE); + return; + } + lck.unlock(); + + if (kill) { + _beginthread(dbpanic, 0, NULL); + Sleep(INFINITE); + } +} + /////////////////////////////////////////////////////////////////////////////// // MIDatabaseChecker @@ -179,7 +226,7 @@ int CDbxMdb::Start(DBCHeckCallback *callback) return ERROR_SUCCESS; } -int CDbxMdb::CheckDb(int phase, int firstTime) +int CDbxMdb::CheckDb(int, int) { return ERROR_OUT_OF_PAPER; diff --git a/plugins/Dbx_mdb/src/dbintf.h b/plugins/Dbx_mdb/src/dbintf.h index cb1b238ee1..16f5a7de42 100644 --- a/plugins/Dbx_mdb/src/dbintf.h +++ b/plugins/Dbx_mdb/src/dbintf.h @@ -124,6 +124,8 @@ struct CDbxMdb : public MIDatabase, public MIDatabaseChecker, public MZeroedObje int Create(void); int Check(void); + void DatabaseCorruption(const TCHAR *ptszText); + void ToggleEncryption(void); void StoreKey(void); void SetPassword(const TCHAR *ptszPassword); @@ -209,7 +211,6 @@ public: protected: MDB_env *m_pMdbEnv; - MDB_txn *m_txn; HANDLE hSettingChangeEvent, hContactDeletedEvent, hContactAddedEvent, hEventMarkedRead; @@ -245,7 +246,7 @@ protected: LIST m_lResidentSettings; HANDLE hEventAddedEvent, hEventDeletedEvent, hEventFilterAddedEvent; MCONTACT m_hLastCachedContact; - ModuleName *m_lastmn; + int m_maxModuleID; void AddToList(char *name, DWORD ofs); DWORD FindExistingModuleNameOfs(const char *szName); diff --git a/plugins/Dbx_mdb/src/dbmodulechain.cpp b/plugins/Dbx_mdb/src/dbmodulechain.cpp index 6f9a8fc15e..70e843111a 100644 --- a/plugins/Dbx_mdb/src/dbmodulechain.cpp +++ b/plugins/Dbx_mdb/src/dbmodulechain.cpp @@ -29,37 +29,57 @@ void CDbxMdb::AddToList(char *name, DWORD ofs) mn->name = name; mn->ofs = ofs; + if (m_lMods.getIndex(mn) != -1) + DatabaseCorruption(_T("%s (Module Name not unique)")); m_lMods.insert(mn); + + if (m_lOfs.getIndex(mn) != -1) + DatabaseCorruption(_T("%s (Module Offset not unique)")); m_lOfs.insert(mn); } int CDbxMdb::InitModuleNames(void) { + m_maxModuleID = 0; + + MDB_txn *txn; + mdb_txn_begin(m_pMdbEnv, NULL, MDB_RDONLY, &txn); + mdb_open(txn, "modules", MDB_CREATE | MDB_INTEGERKEY, &m_dbModules); + MDB_cursor *cursor; - mdb_cursor_open(m_txn, m_dbModules, &cursor); + mdb_cursor_open(txn, m_dbModules, &cursor); int rc, moduleId; - char moduleName[100]; - MDB_val key = { sizeof(int), &moduleId }, data = { sizeof(moduleName), moduleName }; - while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) - AddToList(moduleName, moduleId); + char valueBuf[100]; + MDB_val key = { sizeof(int), &moduleId }, data = { sizeof(valueBuf), valueBuf }; + + while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { + DBModuleName *pmod = (DBModuleName*)valueBuf; + if (pmod->signature != DBMODULENAME_SIGNATURE) + DatabaseCorruption(NULL); + + char *pVal = (char*)HeapAlloc(m_hModHeap, 0, pmod->cbName+1); + memcpy(pVal, pmod->name, pmod->cbName); + pVal[pmod->cbName] = 0; + + AddToList(pVal, moduleId); + + if (moduleId > m_maxModuleID) + m_maxModuleID = moduleId; + } mdb_cursor_close(cursor); + mdb_txn_abort(txn); return 0; } DWORD CDbxMdb::FindExistingModuleNameOfs(const char *szName) { ModuleName mn = { (char*)szName, 0 }; - if (m_lastmn && !strcmp(mn.name, m_lastmn->name)) - return m_lastmn->ofs; int index = m_lMods.getIndex(&mn); - if (index != -1) { - ModuleName *pmn = m_lMods[index]; - m_lastmn = pmn; - return pmn->ofs; - } + if (index != -1) + return m_lMods[index]->ofs; return 0; } @@ -77,11 +97,24 @@ DWORD CDbxMdb::GetModuleNameOfs(const char *szName) int nameLen = (int)strlen(szName); // need to create the module name + int newIdx = ++m_maxModuleID; + DBModuleName *pmod = (DBModuleName*)_alloca(sizeof(DBModuleName) + nameLen); + pmod->signature = DBMODULENAME_SIGNATURE; + pmod->cbName = (char)nameLen; + strcpy(pmod->name, szName); + + MDB_val key = { sizeof(int), &newIdx }, data = { sizeof(DBModuleName) + nameLen, pmod }; + + MDB_txn *txn; + mdb_txn_begin(m_pMdbEnv, NULL, 0, &txn); + mdb_open(txn, "modules", MDB_CREATE | MDB_INTEGERKEY, &m_dbModules); + mdb_put(txn, m_dbModules, &key, &data, 0); + mdb_txn_commit(txn); // add to cache char *mod = (char*)HeapAlloc(m_hModHeap, 0, nameLen + 1); strcpy(mod, szName); - AddToList(mod, -1); + AddToList(mod, newIdx); // quit return -1; @@ -89,16 +122,10 @@ DWORD CDbxMdb::GetModuleNameOfs(const char *szName) char* CDbxMdb::GetModuleNameByOfs(DWORD ofs) { - if (m_lastmn && m_lastmn->ofs == ofs) - return m_lastmn->name; - ModuleName mn = { NULL, ofs }; int index = m_lOfs.getIndex(&mn); - if (index != -1) { - ModuleName *pmn = m_lOfs[index]; - m_lastmn = pmn; - return pmn->name; - } + if (index != -1) + return m_lOfs[index]->name; return NULL; } diff --git a/plugins/Dbx_mdb/src/dbsettings.cpp b/plugins/Dbx_mdb/src/dbsettings.cpp index 46d3540185..099625a1d2 100644 --- a/plugins/Dbx_mdb/src/dbsettings.cpp +++ b/plugins/Dbx_mdb/src/dbsettings.cpp @@ -79,6 +79,7 @@ int CDbxMdb::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR mir_cslock lck(m_csDbAccess); +LBL_Seek: char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); log3("get [%08p] %s (%p)", hContact, szCachedSettingName, szCachedSettingName); @@ -116,6 +117,20 @@ int CDbxMdb::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR if (szCachedSettingName[-1] != 0) return 1; + DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; + + DWORD ofsModuleName = GetModuleNameOfs(szModule); + + // try to get the missing mc setting from the active sub + if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { + if (contactID = db_mc_getDefault(contactID)) { + if (szModule = GetContactProto(contactID)) { + moduleNameLen = (int)strlen(szModule); + goto LBL_Seek; + } + } + } + return 1; } diff --git a/plugins/Dbx_mdb/src/lmdb/mdb.c b/plugins/Dbx_mdb/src/lmdb/mdb.c index f6fd68b1cc..996683cd08 100644 --- a/plugins/Dbx_mdb/src/lmdb/mdb.c +++ b/plugins/Dbx_mdb/src/lmdb/mdb.c @@ -216,7 +216,7 @@ union semun { #ifdef _WIN32 #define MDB_USE_HASH 1 #define MDB_PIDLOCK 0 -#define THREAD_RET DWORD +#define THREAD_RET DWORD WINAPI #define pthread_t HANDLE #define pthread_mutex_t HANDLE #define pthread_cond_t HANDLE -- cgit v1.2.3