DWORD CDb3Mmap::PeekEvent(DWORD ofs, DWORD dwContactID, DBEvent &dbe) { if (m_dbHeader.version >= DB_095_1_VERSION) return PeekSegment(ofs, &dbe, sizeof(DBEvent)); DBEvent_094 oldEvent; DWORD ret = PeekSegment(ofs, &oldEvent, sizeof(oldEvent)); if (ret != ERROR_SUCCESS) return ret; dbe.signature = oldEvent.signature; dbe.contactID = dwContactID; memcpy(&dbe.ofsPrev, &oldEvent.ofsPrev, sizeof(oldEvent) - sizeof(DWORD)); return ERROR_SUCCESS; }
int WorkAggressive(int firstTime) { PBYTE buf; int blockBytes,i; if(firstTime) { if(!opts.bAggressive) return ERROR_NO_MORE_ITEMS; AddToStatus(STATUS_MESSAGE,TranslateT("Performing aggressive pass")); ofsCurrent=0; } blockBytes=min(BLOCKSIZE+3,(int)(sourceFileSize-ofsCurrent)); if(blockBytes<=0) return ERROR_NO_MORE_ITEMS; buf=new BYTE[blockBytes]; if(PeekSegment(ofsCurrent,buf,blockBytes)!=ERROR_SUCCESS) return ERROR_READ_FAULT; blockBytes-=3; for(i=0;i<blockBytes;i++) { if(buf[i]) { if((*(PDWORD)&buf[i]&0x00FFFFFF)!=0xDECADE) AddToStatus(STATUS_WARNING,TranslateT("Aggressive: random junk at %08X: skipping"),ofsCurrent+i); else { //TODO: give user the option of placing manually AddToStatus(STATUS_ERROR,TranslateT("Aggressive: unlinked data at %08X: can't automatically place"),ofsCurrent+i); } for(;i<blockBytes;i++) if(buf[i]==0) {i--; break;} } } delete[] buf; ofsCurrent+=BLOCKSIZE; return ERROR_SUCCESS; }
int WorkSettingsChain(DWORD ofsContact,DBContact *dbc,int firstTime) { DBContactSettings *dbcsNew,dbcsOld; DWORD ofsDestThis; int ret; if(firstTime) { ofsDestPrevSettings=0; ofsThisSettings=dbc->ofsFirstSettings; dbc->ofsFirstSettings=0; } if(ofsThisSettings==0) return ERROR_NO_MORE_ITEMS; if(!SignatureValid(ofsThisSettings,DBCONTACTSETTINGS_SIGNATURE)) { AddToStatus(STATUS_ERROR,TranslateT("Settings chain corrupted, further entries ignored")); return ERROR_NO_MORE_ITEMS; } if(PeekSegment(ofsThisSettings,&dbcsOld,sizeof(dbcsOld))!=ERROR_SUCCESS) return ERROR_NO_MORE_ITEMS; if(dbcsOld.cbBlob>256*1024 || dbcsOld.cbBlob==0) { AddToStatus(STATUS_ERROR,TranslateT("Infeasibly large settings blob: skipping")); ofsThisSettings=dbcsOld.ofsNext; return ERROR_SUCCESS; } dbcsNew=(DBContactSettings*)_malloca(offsetof(DBContactSettings,blob)+dbcsOld.cbBlob); if((ret=ReadSegment(ofsThisSettings,dbcsNew,offsetof(DBContactSettings,blob)+dbcsOld.cbBlob))!=ERROR_SUCCESS) { if(ret!=ERROR_HANDLE_EOF) { //eof is OK because blank space at the end doesn't matter return ERROR_NO_MORE_ITEMS; } } if((dbcsNew->ofsModuleName=ConvertModuleNameOfs(dbcsOld.ofsModuleName))==0) { ofsThisSettings=dbcsOld.ofsNext; return ERROR_SUCCESS; } if(dbcsNew->blob[0]==0) { AddToStatus(STATUS_MESSAGE,TranslateT("Empty settings group at %08X: deleting"),ofsThisSettings); ofsThisSettings=dbcsOld.ofsNext; return ERROR_SUCCESS; } dbcsNew->ofsNext=0; //TODO? validate all settings in blob/compact if necessary if((ofsDestThis=WriteSegment(WSOFS_END,dbcsNew,offsetof(DBContactSettings,blob)+dbcsNew->cbBlob))==WS_ERROR) { return ERROR_HANDLE_DISK_FULL; } if(ofsDestPrevSettings) WriteSegment(ofsDestPrevSettings+offsetof(DBContactSettings,ofsNext),&ofsDestThis,sizeof(DWORD)); else dbc->ofsFirstSettings=ofsDestThis; ofsDestPrevSettings=ofsDestThis; ofsThisSettings=dbcsOld.ofsNext; return ERROR_SUCCESS; }
int CDb3Mmap::ReadSegment(DWORD ofs, PVOID buf, int cbBytes) { int ret = PeekSegment(ofs, buf, cbBytes); if (ret != ERROR_SUCCESS && ret != ERROR_HANDLE_EOF) return ret; if (cb->bAggressive) { if (ofs + cbBytes > sourceFileSize) { cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Can't write to working file, aggressive mode may be too aggressive now")); memset((m_pDbCache + ofs), 0, (sourceFileSize - ofs)); } else memset((m_pDbCache + ofs), 0, cbBytes); } cb->spaceProcessed += cbBytes; return ERROR_SUCCESS; }
int ReadSegment(DWORD ofs,PVOID buf,int cbBytes) { int ret; ret=PeekSegment(ofs,buf,cbBytes); if(ret!=ERROR_SUCCESS && ret!=ERROR_HANDLE_EOF) return ret; if(opts.bAggressive) { if (ofs+cbBytes>sourceFileSize) { AddToStatus(STATUS_WARNING,TranslateT("Can't write to working file, aggressive mode may be too aggressive now")); ZeroMemory(opts.pFile+ofs,sourceFileSize-ofs); } else ZeroMemory(opts.pFile+ofs,cbBytes); } spaceProcessed+=cbBytes; return ERROR_SUCCESS; }
int WorkModuleChain(int firstTime) { DBModuleName moduleName,*newModName; if(firstTime) { AddToStatus(STATUS_MESSAGE,TranslateT("Processing module name chain")); modChainCount=0; last_mod = 0; if(modChain!=NULL) free(modChain); modChain = (ModChainEntry*)malloc(sizeof(ModChainEntry)); phase=0; ofsCurrent=dbhdr.ofsFirstModuleName; } switch(phase) { case 0: if(ofsCurrent==0) { phase++; return ERROR_SUCCESS; } if(!SignatureValid(ofsCurrent,DBMODULENAME_SIGNATURE)) { AddToStatus(STATUS_ERROR,TranslateT("Module chain corrupted, further entries ignored")); phase++; return ERROR_SUCCESS; } if(PeekSegment(ofsCurrent,&moduleName,offsetof(DBModuleName,name))!=ERROR_SUCCESS) { phase++; return ERROR_SUCCESS; } if(moduleName.cbName>256) AddToStatus(STATUS_WARNING,TranslateT("Unreasonably long module name, skipping")); else { modChain=(ModChainEntry*)realloc(modChain,sizeof(ModChainEntry)*++modChainCount); modChain[modChainCount-1].ofsOld=ofsCurrent; modChain[modChainCount-1].size=offsetof(DBModuleName,name)+moduleName.cbName; modChain[modChainCount-1].ofsNew=0; if (moduleName.cbName) PeekSegment(ofsCurrent+offsetof(DBModuleName,name),&modChain[modChainCount-1].name,moduleName.cbName); modChain[modChainCount-1].name[moduleName.cbName]=0; } ofsCurrent=moduleName.ofsNext; break; case 1: ofsLast = 0; iCurrentModName=0; dbhdr.ofsFirstModuleName=0; phase++; case 2: if(iCurrentModName>=modChainCount) { DWORD dw = 0; if(ofsLast) WriteSegment(ofsLast+offsetof(DBModuleName,ofsNext),&dw,sizeof(DWORD)); return ERROR_NO_MORE_ITEMS; } if(modChain[iCurrentModName].ofsNew==0) { newModName=(DBModuleName*)_malloca(modChain[iCurrentModName].size); if(ReadSegment(modChain[iCurrentModName].ofsOld,newModName,modChain[iCurrentModName].size)!=ERROR_SUCCESS) return ERROR_NO_MORE_ITEMS; if((modChain[iCurrentModName].ofsNew=WriteSegment(WSOFS_END,newModName,modChain[iCurrentModName].size))==WS_ERROR) return ERROR_HANDLE_DISK_FULL; { // check duplicated modulenames int i, n=0; for(i=iCurrentModName+1;i<modChainCount;i++) if(!strcmp(modChain[i].name, modChain[iCurrentModName].name)) { modChain[i].ofsNew = modChain[iCurrentModName].ofsNew; n++; } if (n) AddToStatus(STATUS_WARNING,TranslateT("Module name '%s' is not unique: %d duplicates found)"), modChain[iCurrentModName].name,n); } if(iCurrentModName==0) dbhdr.ofsFirstModuleName=modChain[iCurrentModName].ofsNew; else if(WriteSegment(ofsLast+offsetof(DBModuleName,ofsNext),&modChain[iCurrentModName].ofsNew,sizeof(DWORD))==WS_ERROR) return ERROR_HANDLE_DISK_FULL; ofsLast = modChain[iCurrentModName].ofsNew; } iCurrentModName++; break; } return ERROR_SUCCESS; }
int CDb3Mmap::WorkModuleChain(int firstTime) { DBModuleName moduleName, *newModName; if (firstTime) { cb->pfnAddLogMessage(STATUS_MESSAGE, TranslateT("Processing module name chain")); modChainCount = 0; last_mod = 0; free(modChain); modChain = (ModChainEntry*)malloc(sizeof(ModChainEntry)); phase = 0; ofsCurrent = m_dbHeader.ofsModuleNames; } switch (phase) { case 0: if (ofsCurrent == 0) { phase++; return ERROR_SUCCESS; } if (!SignatureValid(ofsCurrent, DBMODULENAME_SIGNATURE)) { cb->pfnAddLogMessage(STATUS_ERROR, TranslateT("Module chain corrupted, further entries ignored")); phase++; return ERROR_SUCCESS; } if (PeekSegment(ofsCurrent, &moduleName, offsetof(DBModuleName, name)) != ERROR_SUCCESS) { phase++; return ERROR_SUCCESS; } modChain = (ModChainEntry*)realloc(modChain, sizeof(ModChainEntry)*++modChainCount); modChain[modChainCount - 1].ofsOld = ofsCurrent; modChain[modChainCount - 1].size = offsetof(DBModuleName, name) + moduleName.cbName; modChain[modChainCount - 1].ofsNew = 0; if (moduleName.cbName) PeekSegment(ofsCurrent + offsetof(DBModuleName, name), &modChain[modChainCount - 1].name, moduleName.cbName); modChain[modChainCount - 1].name[moduleName.cbName] = 0; ofsCurrent = moduleName.ofsNext; break; case 1: ofsLast = 0; iCurrentModName = 0; m_dbHeader.ofsModuleNames = 0; phase++; case 2: if (iCurrentModName >= modChainCount) { DWORD dw = 0; if (ofsLast) WriteSegment(ofsLast + offsetof(DBModuleName, ofsNext), &dw, sizeof(DWORD)); return ERROR_NO_MORE_ITEMS; } if (modChain[iCurrentModName].ofsNew == 0) { newModName = (DBModuleName*)_alloca(modChain[iCurrentModName].size); if (ReadSegment(modChain[iCurrentModName].ofsOld, newModName, modChain[iCurrentModName].size) != ERROR_SUCCESS) return ERROR_NO_MORE_ITEMS; if ((modChain[iCurrentModName].ofsNew = WriteSegment(WSOFS_END, newModName, modChain[iCurrentModName].size)) == WS_ERROR) return ERROR_HANDLE_DISK_FULL; // check duplicated modulenames int i, n = 0; for (i = iCurrentModName + 1; i < modChainCount; i++) if (!mir_strcmp(modChain[i].name, modChain[iCurrentModName].name)) { modChain[i].ofsNew = modChain[iCurrentModName].ofsNew; n++; } if (n) { TCHAR szModuleName[257]; MultiByteToWideChar(CP_ACP, 0, modChain[iCurrentModName].name, -1, szModuleName, _countof(szModuleName)); TCHAR *pszModuleName = szModuleName; cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Module name '%s' is not unique: %d duplicates found"), pszModuleName, n); } if (iCurrentModName == 0) m_dbHeader.ofsModuleNames = modChain[iCurrentModName].ofsNew; else if (WriteSegment(ofsLast + offsetof(DBModuleName, ofsNext), &modChain[iCurrentModName].ofsNew, sizeof(DWORD)) == WS_ERROR) return ERROR_HANDLE_DISK_FULL; ofsLast = modChain[iCurrentModName].ofsNew; } iCurrentModName++; break; } return ERROR_SUCCESS; }
int CDb3Mmap::WorkEventChain(DWORD ofsContact, DBContact *dbc, int firstTime) { DBEvent *dbeNew, dbeOld; DBEvent *dbePrev = NULL; DWORD ofsDestThis; int isUnread = 0; if (firstTime) { dbePrevEvent = NULL; ofsPrevEvent = 0; ofsDestPrevEvent = 0; ofsThisEvent = dbc->ofsFirstEvent; eventCount = 0; backLookup = 0; lastTimestamp = 0; ofsFirstUnread = tsFirstUnread = 0; if (cb->bEraseHistory) { dbc->eventCount = 0; dbc->ofsFirstEvent = 0; dbc->ofsLastEvent = 0; dbc->ofsFirstUnread = 0; dbc->tsFirstUnread = 0; return ERROR_NO_MORE_ITEMS; } } if (ofsThisEvent == 0) { FinishUp(ofsDestPrevEvent, dbc); return ERROR_NO_MORE_ITEMS; } if (!SignatureValid(ofsThisEvent, DBEVENT_SIGNATURE)) { DWORD ofsNew = 0; DWORD ofsTmp = dbc->ofsLastEvent; if (!backLookup && ofsTmp) { backLookup = 1; while (SignatureValid(ofsTmp, DBEVENT_SIGNATURE)) { if (PeekSegment(ofsTmp, &dbeOld, sizeof(dbeOld)) != ERROR_SUCCESS) break; ofsNew = ofsTmp; ofsTmp = dbeOld.ofsPrev; } } if (ofsNew) { cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event chain corrupted, trying to recover...")); ofsThisEvent = ofsNew; } else { cb->pfnAddLogMessage(STATUS_ERROR, TranslateT("Event chain corrupted, further entries ignored")); FinishUp(ofsDestPrevEvent, dbc); return ERROR_NO_MORE_ITEMS; } } if (PeekSegment(ofsThisEvent, &dbeOld, sizeof(dbeOld)) != ERROR_SUCCESS) { FinishUp(ofsDestPrevEvent, dbc); return ERROR_NO_MORE_ITEMS; } if (firstTime) { if (dbeOld.ofsPrev != 0) cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("First event not marked as such: correcting")); dbeOld.ofsPrev = 0; lastTimestamp = dbeOld.timestamp; } if (dbeOld.flags & 1) dbeOld.flags &= ~1; if (dbeOld.flags & ~DBEF_ALL) { cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Extra flags found in event: removing")); dbeOld.flags &= DBEF_ALL; } if (!(dbeOld.flags & (DBEF_READ | DBEF_SENT))) { if (cb->bMarkRead) dbeOld.flags |= DBEF_READ; else if (ofsFirstUnread == 0) { if (dbc->ofsFirstUnread != ofsThisEvent || dbc->tsFirstUnread != dbeOld.timestamp) cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("First unread event marked wrong: fixing")); isUnread = 1; } } if (dbeOld.cbBlob > 1024 * 1024 || dbeOld.cbBlob == 0) { cb->pfnAddLogMessage(STATUS_ERROR, TranslateT("Infeasibly large event blob: skipping")); ofsThisEvent = dbeOld.ofsNext; return ERROR_SUCCESS; } if (dbePrevEvent && dbeOld.timestamp == lastTimestamp) { int len = offsetof(DBEvent, blob) + dbePrevEvent->cbBlob; dbePrev = (DBEvent*)malloc(len); memcpy(dbePrev, dbePrevEvent, len); } if (offsetof(DBEvent, blob) + dbeOld.cbBlob > memsize) { memsize = offsetof(DBEvent, blob) + dbeOld.cbBlob; memblock = (DBEvent*)realloc(memblock, memsize); } dbeNew = memblock; if (ReadSegment(ofsThisEvent, dbeNew, offsetof(DBEvent, blob) + dbeOld.cbBlob) != ERROR_SUCCESS) { FinishUp(ofsDestPrevEvent, dbc); return ERROR_NO_MORE_ITEMS; } if ((dbeNew->ofsModuleName = ConvertModuleNameOfs(dbeOld.ofsModuleName)) == 0) { ofsThisEvent = dbeOld.ofsNext; return ERROR_SUCCESS; } if (!firstTime && dbeOld.ofsPrev != ofsPrevEvent) cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event not backlinked correctly: fixing")); dbeNew->flags = dbeOld.flags; dbeNew->ofsPrev = ofsDestPrevEvent; dbeNew->ofsNext = 0; if (dbeNew->contactID == 0) dbeNew->contactID = dbc->dwContactID; if (dbeOld.wEventType == EVENTTYPE_MESSAGE && cb->bConvertUtf && !(dbeOld.flags & DBEF_ENCRYPTED)) { DWORD oldSize = dbeNew->cbBlob; BYTE* pOldMemo = (BYTE*)_alloca(dbeNew->cbBlob); memcpy(pOldMemo, dbeNew->blob, dbeNew->cbBlob); MoveMemory(dbeNew->blob, pOldMemo, dbeNew->cbBlob); // decode ConvertOldEvent(dbeNew); if (dbeNew->cbBlob > oldSize) pOldMemo = (BYTE*)_alloca(dbeNew->cbBlob); memcpy(pOldMemo, dbeNew->blob, dbeNew->cbBlob); MoveMemory(dbeNew->blob, pOldMemo, dbeNew->cbBlob); // encode } if (dbePrev) { if (dbePrev->cbBlob == dbeNew->cbBlob && dbePrev->ofsModuleName == dbeNew->ofsModuleName && dbePrev->wEventType == dbeNew->wEventType && (dbePrev->flags & DBEF_SENT) == (dbeNew->flags & DBEF_SENT) && !memcmp(dbePrev->blob, dbeNew->blob, dbeNew->cbBlob)) { cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Duplicate event was found: skipping")); if (dbc->eventCount) dbc->eventCount--; free(dbePrev); // ofsDestPrevEvent is still the same! ofsPrevEvent = ofsThisEvent; ofsThisEvent = dbeOld.ofsNext; return ERROR_SUCCESS; } free(dbePrev); } else if (!firstTime && dbeNew->timestamp < lastTimestamp) { DWORD found = 0; DBEvent dbeTmp; DWORD ofsTmp; if (cb->bCheckOnly) { if (!cb->bAggressive) { ofsTmp = dbeOld.ofsPrev; while (PeekSegment(ofsTmp, &dbeTmp, sizeof(dbeTmp)) == ERROR_SUCCESS) { if (dbeTmp.ofsPrev == ofsContact) { found = 1; break; } if (dbeTmp.timestamp < dbeNew->timestamp) { found = 2; break; } ofsTmp = dbeTmp.ofsPrev; } } cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event position in chain is not correct")); } else { ofsTmp = ofsDestPrevEvent; while (ReadWrittenSegment(ofsTmp, &dbeTmp, sizeof(dbeTmp)) == ERROR_SUCCESS) { if (dbeTmp.ofsPrev == ofsContact) { found = 1; break; } if (dbeTmp.timestamp < dbeNew->timestamp) { found = 2; break; } ofsTmp = dbeTmp.ofsPrev; } if (found) cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event position in chain is not correct: fixing")); else cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event position in chain is not correct: unable to fix")); } // insert before FIRST if (found == 1 && !cb->bCheckOnly) { dbeNew->ofsPrev = 0; dbeNew->ofsNext = dbc->ofsFirstEvent; ofsDestThis = WriteEvent(dbeNew); if (!ofsDestThis) return ERROR_HANDLE_DISK_FULL; if (isUnread && tsFirstUnread >= dbeNew->timestamp) { ofsFirstUnread = ofsDestThis; tsFirstUnread = dbeNew->timestamp; } // fix first event WriteOfsNextToPrevious(0, dbc, ofsDestThis); // fix next event WriteSegment(dbeNew->ofsNext + offsetof(DBEvent, ofsPrev), &ofsDestThis, sizeof(DWORD)); } else if (found == 2 && !cb->bCheckOnly) { dbeNew->ofsPrev = ofsTmp; dbeNew->ofsNext = dbeTmp.ofsNext; ofsDestThis = WriteEvent(dbeNew); if (!ofsDestThis) return ERROR_HANDLE_DISK_FULL; if (isUnread && tsFirstUnread >= dbeNew->timestamp) { ofsFirstUnread = ofsDestThis; tsFirstUnread = dbeNew->timestamp; } // fix previous event WriteOfsNextToPrevious(dbeNew->ofsPrev, dbc, ofsDestThis); // fix next event WriteSegment(dbeNew->ofsNext + offsetof(DBEvent, ofsPrev), &ofsDestThis, sizeof(DWORD)); } if (found) { eventCount++; // ofsDestPrevEvent is still the same! ofsPrevEvent = ofsThisEvent; ofsThisEvent = dbeOld.ofsNext; return ERROR_SUCCESS; } } lastTimestamp = dbeNew->timestamp; dbePrevEvent = dbeNew; ofsDestThis = WriteEvent(dbeNew); if (!ofsDestThis) return ERROR_HANDLE_DISK_FULL; if (isUnread) { ofsFirstUnread = ofsDestThis; tsFirstUnread = dbeOld.timestamp; } eventCount++; WriteOfsNextToPrevious(ofsDestPrevEvent, dbc, ofsDestThis); ofsDestPrevEvent = ofsDestThis; ofsPrevEvent = ofsThisEvent; ofsThisEvent = dbeOld.ofsNext; return ERROR_SUCCESS; }