void Map() { hMap = CreateFileMapping(hDbFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL); if (hMap) pDbCache = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS/*FILE_MAP_WRITE*/, 0, 0 ,0); else DatabaseCorruption( _T("%s (CreateFileMapping failed. Code: %d)")); if (!pDbCache) DatabaseCorruption( _T("%s (MapViewOfFile failed. Code: %d)")); }
void CDbxKV::AddToList(char *name, DWORD ofs) { ModuleName *mn = (ModuleName*)HeapAlloc(m_hModHeap, 0, sizeof(ModuleName)); 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); }
void ReMap(DWORD needed) { KillTimer(NULL,flushBuffersTimerId); log3("remapping %d + %d (file end: %d)",dwFileSize,needed,dbHeader.ofsFileEnd); if (needed > ChunkSize) { if ((needed + dwFileSize) - dbHeader.ofsFileEnd > ChunkSize) DatabaseCorruption( _T("%s (Too large increment)")); else { DWORD x = dbHeader.ofsFileEnd/ChunkSize; dwFileSize = (x+1)*ChunkSize; } } else dwFileSize += ChunkSize; // FlushViewOfFile(pDbCache, 0); UnmapViewOfFile(pDbCache); pDbCache = NULL; CloseHandle(hMap); Map(); }
//this function caches results static DWORD GetSettingsGroupOfsByModuleNameOfs(struct DBContact *dbc,DWORD ofsContact,DWORD ofsModuleName) { struct DBContactSettings *dbcs; DWORD ofsThis; int i; for(i=0;i<SETTINGSGROUPOFSCOUNT;i++) { if(settingsGroupOfsCache[i].ofsContact==ofsContact && settingsGroupOfsCache[i].ofsModuleName==ofsModuleName) return settingsGroupOfsCache[i].ofsSettingsGroup; } ofsThis=dbc->ofsFirstSettings; while(ofsThis) { dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL); if(dbcs->signature!=DBCONTACTSETTINGS_SIGNATURE) DatabaseCorruption(); if(dbcs->ofsModuleName==ofsModuleName) { settingsGroupOfsCache[nextSGOCacheEntry].ofsContact=ofsContact; settingsGroupOfsCache[nextSGOCacheEntry].ofsModuleName=ofsModuleName; settingsGroupOfsCache[nextSGOCacheEntry].ofsSettingsGroup=ofsThis; if(++nextSGOCacheEntry==SETTINGSGROUPOFSCOUNT) nextSGOCacheEntry=0; return ofsThis; } ofsThis=dbcs->ofsNext; } return 0; }
//we are assumed to be in a mutex here void DBWrite(DWORD ofs,PVOID pData,int bytes) { //write direct, and rely on Windows' write caching DWORD bytesWritten; int i; log2("write %d@%08x",bytes,ofs); SetFilePointer(hDbFile,ofs,NULL,FILE_BEGIN); if (WriteFile(hDbFile,pData,bytes,&bytesWritten,NULL)==0) { DatabaseCorruption(); } logg(); //check if any of the cache sections contain this bit for(i=0; i<CACHESECTIONCOUNT; i++) { if(ofs+bytes>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) { if(ofs<cacheSectionInfo[i].ofsBase) { //don't start at beginning if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,CACHESECTIONSIZE); else CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,bytes-(cacheSectionInfo[i].ofsBase-ofs)); } else { //start at beginning if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE-ofs); else CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,bytes); } } } }
int InitModuleNames(void) { struct DBModuleName *dbmn; DWORD ofsThis; int nameLen; char *mod; hModHeap=HeapCreate(0,0,0); lMods.sortFunc=ModCompare; lMods.increment=50; lOfs.sortFunc=OfsCompare; lOfs.increment=50; ofsThis=dbHeader.ofsFirstModuleName; dbmn=(struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL); while(ofsThis) { if(dbmn->signature!=DBMODULENAME_SIGNATURE) DatabaseCorruption(NULL); nameLen=dbmn->cbName; mod = (char*)HeapAlloc(hModHeap,0,nameLen+1); CopyMemory(mod,DBRead(ofsThis+offsetof(struct DBModuleName,name),nameLen,NULL),nameLen); mod[nameLen] = 0; AddToList(mod, nameLen, ofsThis); ofsThis=dbmn->ofsNext; dbmn=(struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL); } CreateServiceFunction(MS_DB_MODULES_ENUM,EnumModuleNames); return 0; }
int CDbxKV::InitModuleNames(void) { m_maxModuleID = 0; ham_key_t key = { 0 }; ham_record_t rec = { 0 }; cursor_ptr cursor(m_dbModules); if (ham_cursor_move(cursor, &key, &rec, HAM_CURSOR_FIRST) != HAM_SUCCESS) return 0; do { DBModuleName *pmod = (DBModuleName*)rec.data; if (pmod->dwSignature != DBMODULENAME_SIGNATURE) DatabaseCorruption(NULL); char *pVal = (char*)HeapAlloc(m_hModHeap, 0, pmod->cbName+1); memcpy(pVal, pmod->name, pmod->cbName); pVal[pmod->cbName] = 0; int moduleId = *(int*)key.data; AddToList(pVal, moduleId); if (moduleId > m_maxModuleID) m_maxModuleID = moduleId; } while (ham_cursor_move(cursor, &key, &rec, HAM_CURSOR_NEXT) == 0); return 0; }
int CDbxMdb::Load(bool bSkipInit) { if (!Remap()) return EGROKPRF_CANTREAD; if (!bSkipInit) { txn_ptr trnlck(m_pMdbEnv); mdb_open(trnlck, "global", MDB_CREATE | MDB_INTEGERKEY, &m_dbGlobal); mdb_open(trnlck, "contacts", MDB_CREATE | MDB_INTEGERKEY, &m_dbContacts); mdb_open(trnlck, "modules", MDB_CREATE | MDB_INTEGERKEY, &m_dbModules); mdb_open(trnlck, "events", MDB_CREATE | MDB_INTEGERKEY, &m_dbEvents); mdb_open(trnlck, "eventsrt", MDB_CREATE | MDB_INTEGERKEY, &m_dbEventsSort); mdb_open(trnlck, "settings", MDB_CREATE, &m_dbSettings); DWORD keyVal = 1; MDB_val key = { sizeof(DWORD), &keyVal }, data; if (mdb_get(trnlck, m_dbGlobal, &key, &data) == MDB_SUCCESS) { DBHeader *hdr = (DBHeader*)data.mv_data; if (hdr->dwSignature != DBHEADER_SIGNATURE) DatabaseCorruption(NULL); memcpy(&m_header, data.mv_data, sizeof(m_header)); } else { m_header.dwSignature = DBHEADER_SIGNATURE; m_header.dwVersion = 1; data.mv_data = &m_header; data.mv_size = sizeof(m_header); mdb_put(trnlck, m_dbGlobal, &key, &data, 0); keyVal = 0; DBContact dbc = { DBCONTACT_SIGNATURE, 0, 0, 0 }; data.mv_data = &dbc; data.mv_size = sizeof(dbc); mdb_put(trnlck, m_dbContacts, &key, &data, 0); } trnlck.commit(); if (InitModuleNames()) return EGROKPRF_CANTREAD; if (InitCrypt()) return EGROKPRF_CANTREAD; // everything is ok, go on if (!m_bReadOnly) { // we don't need events in the service mode if (ServiceExists(MS_DB_SETSAFETYMODE)) { hContactDeletedEvent = CreateHookableEvent(ME_DB_CONTACT_DELETED); hContactAddedEvent = CreateHookableEvent(ME_DB_CONTACT_ADDED); hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED); hEventMarkedRead = CreateHookableEvent(ME_DB_EVENT_MARKED_READ); hEventAddedEvent = CreateHookableEvent(ME_DB_EVENT_ADDED); hEventDeletedEvent = CreateHookableEvent(ME_DB_EVENT_DELETED); hEventFilterAddedEvent = CreateHookableEvent(ME_DB_EVENT_FILTER_ADD); } } FillContacts(); } return ERROR_SUCCESS; }
void AddToList(char *name, DWORD len, DWORD ofs) { int index; ModuleName *mn = (ModuleName*)HeapAlloc(hModHeap,0,sizeof(ModuleName)); mn->name = name; mn->ofs = ofs; if (li.List_GetIndex(&lMods,mn,&index)) DatabaseCorruption( _T("%s (Module Name not unique)")); li.List_Insert(&lMods,mn,index); if (li.List_GetIndex(&lOfs,mn,&index)) DatabaseCorruption( _T("%s (Module Offset not unique)")); li.List_Insert(&lOfs,mn,index); }
static VOID CALLBACK DoBufferFlushTimerProc(HWND hwnd,UINT message,UINT idEvent,DWORD dwTime) { if (!pDbCache) return; KillTimer(NULL,flushBuffersTimerId); log0("tflush1"); if (FlushViewOfFile(pDbCache, 0) == 0) DatabaseCorruption(NULL); log0("tflush2"); }
void DBFlush(int setting) { if(!setting) { log0("nflush1"); if(safetyMode && pDbCache) { if (FlushViewOfFile(pDbCache, 0) == 0) DatabaseCorruption(NULL); } log0("nflush2"); return; } KillTimer(NULL,flushBuffersTimerId); flushBuffersTimerId=SetTimer(NULL,flushBuffersTimerId,50,DoBufferFlushTimerProc); }
static DWORD GetSettingsGroupOfsByModuleNameOfs(struct DBContact *dbc,DWORD ofsModuleName) { struct DBContactSettings *dbcs; DWORD ofsThis; ofsThis=dbc->ofsFirstSettings; while(ofsThis) { dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL); if(dbcs->signature!=DBCONTACTSETTINGS_SIGNATURE) DatabaseCorruption(NULL); if(dbcs->ofsModuleName==ofsModuleName) return ofsThis; ofsThis=dbcs->ofsNext; } return 0; }
char* CDb3Mmap::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; } DatabaseCorruption(NULL); return NULL; }
static VOID CALLBACK DoBufferFlushTimerProc(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime) { if (!pDbCache) return; KillTimer(NULL,flushBuffersTimerId); log0("tflush1"); if (FlushViewOfFile(pDbCache, 0) == 0) { if (flushFailTick == 0) flushFailTick = GetTickCount(); else if (GetTickCount() - flushFailTick > 5000) DatabaseCorruption(NULL); } else flushFailTick = 0; log0("tflush2"); }
void DBFlush(int setting) { if(!setting) { log0("nflush1"); if(safetyMode && pDbCache) { if (FlushViewOfFile(pDbCache, 0) == 0) { if (flushFailTick == 0) flushFailTick = GetTickCount(); else if (GetTickCount() - flushFailTick > 5000) DatabaseCorruption(NULL); } else flushFailTick = 0; } log0("nflush2"); return; } KillTimer(NULL,flushBuffersTimerId); flushBuffersTimerId=SetTimer(NULL,flushBuffersTimerId,50,DoBufferFlushTimerProc); }
int CDb3Mmap::InitModuleNames(void) { DWORD ofsThis = m_dbHeader.ofsModuleNames; DBModuleName *dbmn = (struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL); while (ofsThis) { if (dbmn->signature != DBMODULENAME_SIGNATURE) DatabaseCorruption(NULL); int nameLen = dbmn->cbName; char *mod = (char*)HeapAlloc(m_hModHeap,0,nameLen+1); CopyMemory(mod,DBRead(ofsThis + offsetof(struct DBModuleName,name),nameLen,NULL),nameLen); mod[nameLen] = 0; AddToList(mod, nameLen, ofsThis); ofsThis = dbmn->ofsNext; dbmn = (struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL); } return 0; }
char *GetModuleNameByOfs(DWORD ofs) { static ModuleName *lastmn = NULL; ModuleName mn, *pmn; int index; if (lastmn && lastmn->ofs == ofs) return lastmn->name; mn.name = NULL; mn.ofs = ofs; if (li.List_GetIndex(&lOfs,&mn,&index)) { pmn = (ModuleName*)lOfs.items[index]; lastmn = pmn; return pmn->name; } DatabaseCorruption(NULL); return NULL; }
void CDbxKV::FillContacts() { m_contactCount = 0; ham_key_t key = { 0 }; ham_record_t rec = { 0 }; cursor_ptr cursor(m_dbContacts); if (ham_cursor_move(cursor, &key, &rec, HAM_CURSOR_FIRST) != HAM_SUCCESS) // empty table? return; do { DBContact *dbc = (DBContact*)rec.data; if (dbc->dwSignature != DBCONTACT_SIGNATURE) DatabaseCorruption(NULL); DBCachedContact *cc = m_cache->AddContactToCache(*(DWORD*)key.data); cc->dbc.dwSignature = DBCONTACT_SIGNATURE; cc->dbc.dwEventCount = dbc->dwEventCount; cc->dbc.dwFirstUnread = dbc->dwFirstUnread; cc->dbc.tsFirstUnread = dbc->tsFirstUnread; CheckProto(cc, ""); m_dwMaxContactId = cc->contactID+1; m_contactCount++; DBVARIANT dbv; dbv.type = DBVT_DWORD; cc->nSubs = (0 != GetContactSetting(cc->contactID, META_PROTO, "NumContacts", &dbv)) ? -1 : dbv.dVal; if (cc->nSubs != -1) { cc->pSubs = (MCONTACT*)mir_alloc(cc->nSubs*sizeof(MCONTACT)); for (int i = 0; i < cc->nSubs; i++) { char setting[100]; mir_snprintf(setting, SIZEOF(setting), "Handle%d", i); cc->pSubs[i] = (0 != GetContactSetting(cc->contactID, META_PROTO, setting, &dbv)) ? NULL : dbv.dVal; } } cc->nDefault = (0 != GetContactSetting(cc->contactID, META_PROTO, "Default", &dbv)) ? -1 : dbv.dVal; cc->parentID = (0 != GetContactSetting(cc->contactID, META_PROTO, "ParentMeta", &dbv)) ? NULL : dbv.dVal; } while (ham_cursor_move(cursor, &key, &rec, HAM_CURSOR_NEXT) == HAM_SUCCESS); }
void CDbxKyoto::FillContacts() { m_contactCount = 0; size_t size; cursor_ptr cursor(m_dbContacts); for (cursor->jump(); cursor->step();) { const char *pRec, *pKey = cursor->get(&size, &pRec, &size); DBContact *dbc = (DBContact*)pRec; if (dbc->dwSignature != DBCONTACT_SIGNATURE) DatabaseCorruption(NULL); DBCachedContact *cc = m_cache->AddContactToCache(*(DWORD*)pKey); cc->dbc.dwSignature = DBCONTACT_SIGNATURE; cc->dbc.dwEventCount = dbc->dwEventCount; cc->dbc.dwFirstUnread = dbc->dwFirstUnread; cc->dbc.tsFirstUnread = dbc->tsFirstUnread; CheckProto(cc, ""); m_dwMaxContactId = cc->contactID+1; m_contactCount++; DBVARIANT dbv; dbv.type = DBVT_DWORD; cc->nSubs = (0 != GetContactSetting(cc->contactID, META_PROTO, "NumContacts", &dbv)) ? -1 : dbv.dVal; if (cc->nSubs != -1) { cc->pSubs = (MCONTACT*)mir_alloc(cc->nSubs*sizeof(MCONTACT)); for (int i = 0; i < cc->nSubs; i++) { char setting[100]; mir_snprintf(setting, SIZEOF(setting), "Handle%d", i); cc->pSubs[i] = (0 != GetContactSetting(cc->contactID, META_PROTO, setting, &dbv)) ? NULL : dbv.dVal; } } cc->nDefault = (0 != GetContactSetting(cc->contactID, META_PROTO, "Default", &dbv)) ? -1 : dbv.dVal; cc->parentID = (0 != GetContactSetting(cc->contactID, META_PROTO, "ParentMeta", &dbv)) ? NULL : dbv.dVal; delete[] pKey; } }
STDMETHODIMP_(LONG) CDb3Mmap::DeleteContact(MCONTACT contactID) { if (contactID == 0) // global contact cannot be removed return 1; mir_cslockfull lck(m_csDbAccess); DWORD ofsContact = GetContactOffset(contactID); DBContact *dbc = (DBContact*)DBRead(ofsContact, NULL); if (dbc->signature != DBCONTACT_SIGNATURE) return 1; if (ofsContact == m_dbHeader.ofsUser) { log0("FATAL: del of user chain attempted."); return 1; } lck.unlock(); log0("del contact"); // call notifier while outside mutex NotifyEventHooks(hContactDeletedEvent, contactID, 0); // get back in lck.lock(); // delete settings chain DWORD ofsThis = dbc->ofsFirstSettings; DWORD ofsFirstEvent = dbc->ofsFirstEvent; while (ofsThis) { DBContactSettings *dbcs = (DBContactSettings*)DBRead(ofsThis, NULL); DWORD ofsNext = dbcs->ofsNext; DeleteSpace(ofsThis, offsetof(DBContactSettings, blob) + dbcs->cbBlob); ofsThis = ofsNext; } // delete event chain ofsThis = ofsFirstEvent; while (ofsThis) { DBEvent *dbe = (DBEvent*)DBRead(ofsThis, NULL); DWORD ofsNext = dbe->ofsNext; DeleteSpace(ofsThis, offsetof(DBEvent, blob) + dbe->cbBlob); ofsThis = ofsNext; } // find previous contact in chain and change ofsNext if (m_dbHeader.ofsFirstContact == ofsContact) { m_dbHeader.ofsFirstContact = dbc->ofsNext; DBWrite(0, &m_dbHeader, sizeof(m_dbHeader)); } else { DWORD ofsNext = dbc->ofsNext; ofsThis = m_dbHeader.ofsFirstContact; DBContact *dbcPrev = (DBContact*)DBRead(ofsThis, NULL); while (dbcPrev->ofsNext != ofsContact) { if (dbcPrev->ofsNext == 0) DatabaseCorruption(NULL); ofsThis = dbcPrev->ofsNext; dbcPrev = (DBContact*)DBRead(ofsThis, NULL); } dbcPrev->ofsNext = ofsNext; DBWrite(ofsThis, dbcPrev, sizeof(DBContact)); } // delete contact DeleteSpace(ofsContact, sizeof(DBContact)); // decrement contact count m_dbHeader.contactCount--; DBWrite(0, &m_dbHeader, sizeof(m_dbHeader)); DBFlush(0); // free cache item m_cache->FreeCachedContact(contactID); if (contactID == m_hLastCachedContact) m_hLastCachedContact = NULL; return 0; }
STDMETHODIMP_(BOOL) CDb3Mmap::WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) { if (dbcws == NULL || dbcws->szSetting == NULL || dbcws->szModule == NULL || m_bReadOnly) return 1; // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name int settingNameLen = (int)mir_strlen(dbcws->szSetting); int moduleNameLen = (int)mir_strlen(dbcws->szModule); if (settingNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("WriteContactSetting() got a > 255 setting name length. \n"); #endif return 1; } if (moduleNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("WriteContactSetting() got a > 255 module name length. \n"); #endif return 1; } // used for notifications DBCONTACTWRITESETTING dbcwNotif = *dbcws; if (dbcwNotif.value.type == DBVT_WCHAR) { if (dbcwNotif.value.pszVal != NULL) { char* val = mir_utf8encodeW(dbcwNotif.value.pwszVal); if (val == NULL) return 1; dbcwNotif.value.pszVal = (char*)alloca(mir_strlen(val) + 1); mir_strcpy(dbcwNotif.value.pszVal, val); mir_free(val); dbcwNotif.value.type = DBVT_UTF8; } else return 1; } if (dbcwNotif.szModule == NULL || dbcwNotif.szSetting == NULL) return 1; DBCONTACTWRITESETTING dbcwWork = dbcwNotif; mir_ptr<BYTE> pEncoded(NULL); bool bIsEncrypted = false; switch (dbcwWork.value.type) { case DBVT_BYTE: case DBVT_WORD: case DBVT_DWORD: break; case DBVT_ASCIIZ: case DBVT_UTF8: bIsEncrypted = m_bEncrypted || IsSettingEncrypted(dbcws->szModule, dbcws->szSetting); LBL_WriteString: if (dbcwWork.value.pszVal == NULL) return 1; dbcwWork.value.cchVal = (WORD)mir_strlen(dbcwWork.value.pszVal); if (bIsEncrypted) { size_t len; BYTE *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); if (pResult != NULL) { pEncoded = dbcwWork.value.pbVal = pResult; dbcwWork.value.cpbVal = (WORD)len; dbcwWork.value.type = DBVT_ENCRYPTED; } } break; case DBVT_UNENCRYPTED: dbcwNotif.value.type = dbcwWork.value.type = DBVT_UTF8; goto LBL_WriteString; case DBVT_BLOB: case DBVT_ENCRYPTED: if (dbcwWork.value.pbVal == NULL) return 1; break; default: return 1; } mir_cslockfull lck(m_csDbAccess); DWORD ofsBlobPtr, ofsContact = GetContactOffset(contactID); if (ofsContact == 0) { _ASSERT(false); // contact doesn't exist? return 2; } char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); log3("set [%08p] %s (%p)", hContact, szCachedSettingName, szCachedSettingName); // we don't cache blobs and passwords if (dbcwWork.value.type != DBVT_BLOB && dbcwWork.value.type != DBVT_ENCRYPTED && !bIsEncrypted) { DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); if (pCachedValue != NULL) { bool bIsIdentical = false; if (pCachedValue->type == dbcwWork.value.type) { switch (dbcwWork.value.type) { case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == dbcwWork.value.bVal; break; case DBVT_WORD: bIsIdentical = pCachedValue->wVal == dbcwWork.value.wVal; break; case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == dbcwWork.value.dVal; break; case DBVT_UTF8: case DBVT_ASCIIZ: bIsIdentical = mir_strcmp(pCachedValue->pszVal, dbcwWork.value.pszVal) == 0; break; } if (bIsIdentical) return 0; } m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); } if (szCachedSettingName[-1] != 0) { lck.unlock(); log2(" set resident as %s (%p)", printVariant(&dbcwWork.value), pCachedValue); NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwWork); return 0; } } else m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); log1(" write database as %s", printVariant(&dbcwWork.value)); DWORD ofsModuleName = GetModuleNameOfs(dbcwWork.szModule); DBContact dbc = *(DBContact*)DBRead(ofsContact, NULL); if (dbc.signature != DBCONTACT_SIGNATURE) return 1; // make sure the module group exists PBYTE pBlob; int bytesRequired, bytesRemaining; DBContactSettings dbcs; DWORD ofsSettingsGroup = GetSettingsGroupOfsByModuleNameOfs(&dbc, ofsModuleName); if (ofsSettingsGroup == 0) { //module group didn't exist - make it switch (dbcwWork.value.type) { case DBVT_ASCIIZ: case DBVT_UTF8: bytesRequired = dbcwWork.value.cchVal + 2; break; case DBVT_BLOB: case DBVT_ENCRYPTED: bytesRequired = dbcwWork.value.cpbVal + 2; break; default: bytesRequired = dbcwWork.value.type; } bytesRequired += 2 + settingNameLen; bytesRequired += (DB_SETTINGS_RESIZE_GRANULARITY - (bytesRequired % DB_SETTINGS_RESIZE_GRANULARITY)) % DB_SETTINGS_RESIZE_GRANULARITY; ofsSettingsGroup = CreateNewSpace(bytesRequired + offsetof(DBContactSettings, blob)); dbcs.signature = DBCONTACTSETTINGS_SIGNATURE; dbcs.ofsNext = dbc.ofsFirstSettings; dbcs.ofsModuleName = ofsModuleName; dbcs.cbBlob = bytesRequired; dbcs.blob[0] = 0; dbc.ofsFirstSettings = ofsSettingsGroup; DBWrite(ofsContact, &dbc, sizeof(DBContact)); DBWrite(ofsSettingsGroup, &dbcs, sizeof(DBContactSettings)); ofsBlobPtr = ofsSettingsGroup + offsetof(DBContactSettings, blob); pBlob = (PBYTE)DBRead(ofsBlobPtr, &bytesRemaining); } else { dbcs = *(DBContactSettings*)DBRead(ofsSettingsGroup, &bytesRemaining); // find if the setting exists ofsBlobPtr = ofsSettingsGroup + offsetof(DBContactSettings, blob); pBlob = (PBYTE)DBRead(ofsBlobPtr, &bytesRemaining); while (pBlob[0]) { NeedBytes(settingNameLen + 1); if (pBlob[0] == settingNameLen && !memcmp(pBlob + 1, dbcwWork.szSetting, settingNameLen)) break; NeedBytes(1); MoveAlong(pBlob[0] + 1); NeedBytes(3); MoveAlong(1 + GetSettingValueLength(pBlob)); NeedBytes(1); } // setting already existed, and up to end of name is in cache if (pBlob[0]) { MoveAlong(1 + settingNameLen); // if different type or variable length and length is different NeedBytes(3); if (pBlob[0] != dbcwWork.value.type || ((pBlob[0] == DBVT_ASCIIZ || pBlob[0] == DBVT_UTF8) && *(PWORD)(pBlob + 1) != dbcwWork.value.cchVal) || ((pBlob[0] == DBVT_BLOB || pBlob[0] == DBVT_ENCRYPTED) && *(PWORD)(pBlob + 1) != dbcwWork.value.cpbVal)) { // bin it NeedBytes(3); int nameLen = 1 + settingNameLen; int valLen = 1 + GetSettingValueLength(pBlob); DWORD ofsSettingToCut = ofsBlobPtr - nameLen; MoveAlong(valLen); NeedBytes(1); while (pBlob[0]) { MoveAlong(pBlob[0] + 1); NeedBytes(3); MoveAlong(1 + GetSettingValueLength(pBlob)); NeedBytes(1); } DBMoveChunk(ofsSettingToCut, ofsSettingToCut + nameLen + valLen, ofsBlobPtr + 1 - ofsSettingToCut); ofsBlobPtr -= nameLen + valLen; pBlob = (PBYTE)DBRead(ofsBlobPtr, &bytesRemaining); } else { // replace existing setting at pBlob MoveAlong(1); // skip data type switch (dbcwWork.value.type) { case DBVT_BYTE: DBWrite(ofsBlobPtr, &dbcwWork.value.bVal, 1); break; case DBVT_WORD: DBWrite(ofsBlobPtr, &dbcwWork.value.wVal, 2); break; case DBVT_DWORD: DBWrite(ofsBlobPtr, &dbcwWork.value.dVal, 4); break; case DBVT_BLOB: DBWrite(ofsBlobPtr + 2, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); break; case DBVT_ENCRYPTED: DBWrite(ofsBlobPtr + 2, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); break; case DBVT_UTF8: case DBVT_ASCIIZ: DBWrite(ofsBlobPtr + 2, dbcwWork.value.pszVal, dbcwWork.value.cchVal); break; } // quit DBFlush(1); lck.unlock(); // notify NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); return 0; } } } // cannot do a simple replace, add setting to end of list // pBlob already points to end of list // see if it fits switch (dbcwWork.value.type) { case DBVT_ASCIIZ: case DBVT_UTF8: bytesRequired = dbcwWork.value.cchVal + 2; break; case DBVT_BLOB: case DBVT_ENCRYPTED: bytesRequired = dbcwWork.value.cpbVal + 2; break; default: bytesRequired = dbcwWork.value.type; } bytesRequired += 2 + settingNameLen; bytesRequired += ofsBlobPtr + 1 - (ofsSettingsGroup + offsetof(DBContactSettings, blob)); if ((DWORD)bytesRequired > dbcs.cbBlob) { // doesn't fit: move entire group DBContactSettings *dbcsPrev; DWORD ofsDbcsPrev, ofsNew; InvalidateSettingsGroupOfsCacheEntry(ofsSettingsGroup); bytesRequired += (DB_SETTINGS_RESIZE_GRANULARITY - (bytesRequired % DB_SETTINGS_RESIZE_GRANULARITY)) % DB_SETTINGS_RESIZE_GRANULARITY; // find previous group to change its offset ofsDbcsPrev = dbc.ofsFirstSettings; if (ofsDbcsPrev == ofsSettingsGroup) ofsDbcsPrev = 0; else { dbcsPrev = (DBContactSettings*)DBRead(ofsDbcsPrev, NULL); while (dbcsPrev->ofsNext != ofsSettingsGroup) { if (dbcsPrev->ofsNext == 0) DatabaseCorruption(NULL); ofsDbcsPrev = dbcsPrev->ofsNext; dbcsPrev = (DBContactSettings*)DBRead(ofsDbcsPrev, NULL); } } // create the new one ofsNew = ReallocSpace(ofsSettingsGroup, dbcs.cbBlob + offsetof(DBContactSettings, blob), bytesRequired + offsetof(DBContactSettings, blob)); dbcs.cbBlob = bytesRequired; DBWrite(ofsNew, &dbcs, offsetof(DBContactSettings, blob)); if (ofsDbcsPrev == 0) { dbc.ofsFirstSettings = ofsNew; DBWrite(ofsContact, &dbc, sizeof(DBContact)); } else { dbcsPrev = (DBContactSettings*)DBRead(ofsDbcsPrev, NULL); dbcsPrev->ofsNext = ofsNew; DBWrite(ofsDbcsPrev, dbcsPrev, offsetof(DBContactSettings, blob)); } ofsBlobPtr += ofsNew - ofsSettingsGroup; ofsSettingsGroup = ofsNew; pBlob = (PBYTE)DBRead(ofsBlobPtr, &bytesRemaining); } // we now have a place to put it and enough space: make it DBWrite(ofsBlobPtr, &settingNameLen, 1); DBWrite(ofsBlobPtr + 1, (PVOID)dbcwWork.szSetting, settingNameLen); MoveAlong(1 + settingNameLen); DBWrite(ofsBlobPtr, &dbcwWork.value.type, 1); MoveAlong(1); switch (dbcwWork.value.type) { case DBVT_BYTE: DBWrite(ofsBlobPtr, &dbcwWork.value.bVal, 1); MoveAlong(1); break; case DBVT_WORD: DBWrite(ofsBlobPtr, &dbcwWork.value.wVal, 2); MoveAlong(2); break; case DBVT_DWORD: DBWrite(ofsBlobPtr, &dbcwWork.value.dVal, 4); MoveAlong(4); break; case DBVT_BLOB: DBWrite(ofsBlobPtr, &dbcwWork.value.cpbVal, 2); DBWrite(ofsBlobPtr + 2, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); MoveAlong(2 + dbcwWork.value.cpbVal); break; case DBVT_ENCRYPTED: DBWrite(ofsBlobPtr, &dbcwWork.value.cpbVal, 2); DBWrite(ofsBlobPtr + 2, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); MoveAlong(2 + dbcwWork.value.cpbVal); break; case DBVT_UTF8: case DBVT_ASCIIZ: DBWrite(ofsBlobPtr, &dbcwWork.value.cchVal, 2); DBWrite(ofsBlobPtr + 2, dbcwWork.value.pszVal, dbcwWork.value.cchVal); MoveAlong(2 + dbcwWork.value.cchVal); break; } BYTE zero = 0; DBWrite(ofsBlobPtr, &zero, 1); // quit DBFlush(1); lck.unlock(); // notify NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); return 0; }
static INT_PTR DeleteContact(WPARAM wParam,LPARAM lParam) { struct DBContact *dbc,*dbcPrev; DWORD ofsThis,ofsNext,ofsFirstEvent; struct DBContactSettings *dbcs; struct DBEvent *dbe; int index; if((HANDLE)wParam==NULL) return 1; EnterCriticalSection(&csDbAccess); dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL); if(dbc->signature!=DBCONTACT_SIGNATURE) { LeaveCriticalSection(&csDbAccess); return 1; } if ( (HANDLE)wParam == (HANDLE)dbHeader.ofsUser ) { LeaveCriticalSection(&csDbAccess); log0("FATAL: del of user chain attempted."); return 1; } log0("del contact"); LeaveCriticalSection(&csDbAccess); //call notifier while outside mutex NotifyEventHooks(hContactDeletedEvent,wParam,0); //get back in EnterCriticalSection(&csDbAccess); { DBCachedContactValueList VLtemp; VLtemp.hContact = (HANDLE)wParam; if ( li.List_GetIndex(&lContacts,&VLtemp,&index)) { DBCachedContactValueList *VL = ( DBCachedContactValueList* )lContacts.items[index]; DBCachedContactValue* V = VL->first; while ( V != NULL ) { DBCachedContactValue* V1 = V->next; FreeCachedVariant(&V->value); HeapFree( hCacheHeap, 0, V ); V = V1; } HeapFree( hCacheHeap, 0, VL ); if (VLtemp.hContact == hLastCachedContact) hLastCachedContact = NULL; li.List_Remove(&lContacts,index); } } dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL); //delete settings chain ofsThis=dbc->ofsFirstSettings; ofsFirstEvent=dbc->ofsFirstEvent; while(ofsThis) { dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL); ofsNext=dbcs->ofsNext; DeleteSpace(ofsThis,offsetof(struct DBContactSettings,blob)+dbcs->cbBlob); ofsThis=ofsNext; } //delete event chain ofsThis=ofsFirstEvent; while(ofsThis) { dbe=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL); ofsNext=dbe->ofsNext; DeleteSpace(ofsThis,offsetof(struct DBEvent,blob)+dbe->cbBlob); ofsThis=ofsNext; } //find previous contact in chain and change ofsNext dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL); if(dbHeader.ofsFirstContact==wParam) { dbHeader.ofsFirstContact=dbc->ofsNext; DBWrite(0,&dbHeader,sizeof(dbHeader)); } else { ofsNext=dbc->ofsNext; ofsThis=dbHeader.ofsFirstContact; dbcPrev=(struct DBContact*)DBRead(ofsThis,sizeof(struct DBContact),NULL); while(dbcPrev->ofsNext!=wParam) { if(dbcPrev->ofsNext==0) DatabaseCorruption(NULL); ofsThis=dbcPrev->ofsNext; dbcPrev=(struct DBContact*)DBRead(ofsThis,sizeof(struct DBContact),NULL); } dbcPrev->ofsNext=ofsNext; DBWrite(ofsThis,dbcPrev,sizeof(struct DBContact)); { DBCachedContactValueList VLtemp; VLtemp.hContact = (HANDLE)ofsThis; if ( li.List_GetIndex(&lContacts,&VLtemp,&index)) { DBCachedContactValueList *VL = ( DBCachedContactValueList* )lContacts.items[index]; VL->hNext = ( HANDLE )ofsNext; } } } //delete contact DeleteSpace(wParam,sizeof(struct DBContact)); //decrement contact count dbHeader.contactCount--; DBWrite(0,&dbHeader,sizeof(dbHeader)); DBFlush(0); //quit LeaveCriticalSection(&csDbAccess); return 0; }