From d5d6965af7e69367babf40b7fb1d7fca8617cabe Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 26 Jul 2012 14:56:53 +0000 Subject: dbtool is divided into two parts: DbChecker & appendix for db3x_mmap plugin git-svn-id: http://svn.miranda-ng.org/main/trunk@1195 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Db3x_mmap/src/dbtool/aggressive.cpp | 63 +++++ plugins/Db3x_mmap/src/dbtool/contactchain.cpp | 99 +++++++ plugins/Db3x_mmap/src/dbtool/disk.cpp | 112 ++++++++ plugins/Db3x_mmap/src/dbtool/eventchain.cpp | 363 +++++++++++++++++++++++++ plugins/Db3x_mmap/src/dbtool/finaltasks.cpp | 78 ++++++ plugins/Db3x_mmap/src/dbtool/initialchecks.cpp | 81 ++++++ plugins/Db3x_mmap/src/dbtool/modulechain.cpp | 146 ++++++++++ plugins/Db3x_mmap/src/dbtool/settingschain.cpp | 72 +++++ plugins/Db3x_mmap/src/dbtool/user.cpp | 71 +++++ 9 files changed, 1085 insertions(+) create mode 100644 plugins/Db3x_mmap/src/dbtool/aggressive.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/contactchain.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/disk.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/eventchain.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/finaltasks.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/initialchecks.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/modulechain.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/settingschain.cpp create mode 100644 plugins/Db3x_mmap/src/dbtool/user.cpp (limited to 'plugins/Db3x_mmap/src/dbtool') diff --git a/plugins/Db3x_mmap/src/dbtool/aggressive.cpp b/plugins/Db3x_mmap/src/dbtool/aggressive.cpp new file mode 100644 index 0000000000..7cafb63043 --- /dev/null +++ b/plugins/Db3x_mmap/src/dbtool/aggressive.cpp @@ -0,0 +1,63 @@ +/* +Miranda Database Tool +Copyright (C) 2001-2005 Richard Hughes + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "..\commonheaders.h" + +#define BLOCKSIZE 65536 + +extern DWORD sourceFileSize; +extern DWORD spaceProcessed; +extern DWORD sp; +static DWORD ofsCurrent; + +int WorkAggressive(int firstTime) +{ + int blockBytes,i; + BYTE *buf; + + if (firstTime) { + if (!opts.bAggressive) + return ERROR_NO_MORE_ITEMS; + + AddToStatus(STATUS_MESSAGE,TranslateT("Performing aggressive pass")); + ofsCurrent = 0; + spaceProcessed = 0; + sp = 0; + } + blockBytes = min(BLOCKSIZE+3,(int)(sourceFileSize-ofsCurrent)); + if (blockBytes <= 0) + return ERROR_NO_MORE_ITEMS; + + buf = opts.pFile+ofsCurrent; + blockBytes -= 3; + for(i = 0;i= sourceFileSize) { + AddToStatus(STATUS_ERROR, TranslateT("Invalid offset found (database truncated?)")); + return 0; + } + + sig = *(DWORD*)(opts.pFile+ofs); + + return sig == signature; +} + +int PeekSegment(DWORD ofs, PVOID buf, int cbBytes) +{ + DWORD bytesRead; + + if (ofs >= sourceFileSize) { + AddToStatus(STATUS_ERROR, TranslateT("Invalid offset found")); + return ERROR_SEEK; + } + + if (ofs+cbBytes>sourceFileSize) + bytesRead = sourceFileSize - ofs; + else + bytesRead = cbBytes; + + if (bytesRead == 0) { + AddToStatus(STATUS_ERROR, TranslateT("Error reading, database truncated? (%u)"), GetLastError()); + return ERROR_READ_FAULT; + } + + CopyMemory(buf, opts.pFile+ofs, bytesRead); + + if ((int)bytesReadsourceFileSize) { + 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; +} + +DWORD WriteSegment(DWORD ofs, PVOID buf, int cbBytes) +{ + DWORD bytesWritten; + if (opts.bCheckOnly) return 0xbfbfbfbf; + if (ofs == WSOFS_END) { + ofs = dbhdr.ofsFileEnd; + dbhdr.ofsFileEnd += cbBytes; + } + SetFilePointer(opts.hOutFile, ofs, NULL, FILE_BEGIN); + WriteFile(opts.hOutFile, buf, cbBytes, &bytesWritten, NULL); + if ((int)bytesWritten dbhdr.ofsFileEnd) + return ERROR_SEEK; + + SetFilePointer(opts.hOutFile, ofs, NULL, FILE_BEGIN); + ReadFile(opts.hOutFile, buf, cbBytes, &bytesRead, NULL); + if ((int)bytesReadblob) + 1, msglenW = 0; + if (msglen != (int) dbei->cbBlob) { + int i, count = ((dbei->cbBlob - msglen) / sizeof(WCHAR)); + WCHAR* p = (WCHAR*)&dbei->blob[ msglen ]; + for ( i = 0; i < count; i++) { + if (p[i] == 0) { + msglenW = i; + break; + } } } + else { + if (!is_utf8_string((char*)dbei->blob)) + dbei->flags &= ~DBEF_UTF; + } + + if (msglenW > 0 && msglenW <= msglen) { + char* utf8str = Utf8EncodeW((WCHAR*)&dbei->blob[ msglen ]); + dbei->cbBlob = (DWORD)strlen(utf8str)+1; + dbei->flags |= DBEF_UTF; + if (offsetof(DBEvent,blob)+dbei->cbBlob > memsize) { + memsize = offsetof(DBEvent,blob)+dbei->cbBlob; + memblock = (DBEvent*)realloc(memblock, memsize); + dbei = memblock; + } + memcpy(&dbei->blob, utf8str, dbei->cbBlob); + free(utf8str); +} } + +static void WriteOfsNextToPrevious(DWORD ofsPrev,DBContact *dbc,DWORD ofsNext) +{ + if (ofsPrev) + WriteSegment(ofsPrev+offsetof(DBEvent,ofsNext),&ofsNext,sizeof(DWORD)); + else + dbc->ofsFirstEvent = ofsNext; +} + +static void FinishUp(DWORD ofsLast,DBContact *dbc) +{ + WriteOfsNextToPrevious(ofsLast,dbc,0); + if (eventCount != dbc->eventCount) + AddToStatus(STATUS_WARNING,TranslateT("Event count marked wrongly: correcting")); + dbc->eventCount = eventCount; + dbc->ofsLastEvent = ofsLast; + if (opts.bMarkRead) { + dbc->ofsFirstUnreadEvent = 0; + dbc->timestampFirstUnread = 0; + } + else { + dbc->ofsFirstUnreadEvent = ofsFirstUnread; + dbc->timestampFirstUnread = timestampFirstUnread; + } + if (memsize && memblock) { + free(memblock); + memsize = 0; + memblock = NULL; + } +} + +static DWORD WriteEvent(DBEvent *dbe) +{ + DWORD ofs = WriteSegment(WSOFS_END, dbe, offsetof(DBEvent,blob)+dbe->cbBlob); + if (ofs == WS_ERROR) { + free(memblock); + memblock = NULL; + memsize = 0; + return 0; + } + return ofs; +} + +int 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 = timestampFirstUnread = 0; + if (opts.bEraseHistory) { + dbc->eventCount = 0; + dbc->ofsFirstEvent = 0; + dbc->ofsLastEvent = 0; + dbc->ofsFirstUnreadEvent = 0; + dbc->timestampFirstUnread = 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) { + AddToStatus(STATUS_WARNING,TranslateT("Event chain corrupted, trying to recover...")); + ofsThisEvent = ofsNew; + } else { + AddToStatus(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.flags&DBEF_FIRST)) { + AddToStatus(STATUS_WARNING,TranslateT("First event not marked as such: correcting")); + dbeOld.flags|=DBEF_FIRST; + } + dbeOld.ofsPrev = ofsContact; + lastTimestamp = dbeOld.timestamp; + } + else if (dbeOld.flags&DBEF_FIRST) { + AddToStatus(STATUS_WARNING,TranslateT("Event marked as first which is not: correcting")); + dbeOld.flags&=~DBEF_FIRST; + } + + if (dbeOld.flags&~(DBEF_FIRST|DBEF_READ|DBEF_SENT|DBEF_RTL|DBEF_UTF)) { + AddToStatus(STATUS_WARNING,TranslateT("Extra flags found in event: removing")); + dbeOld.flags&=(DBEF_FIRST|DBEF_READ|DBEF_SENT|DBEF_RTL|DBEF_UTF); + } + + if (!(dbeOld.flags&(DBEF_READ|DBEF_SENT))) { + if (opts.bMarkRead) dbeOld.flags|=DBEF_READ; + else if (ofsFirstUnread == 0) { + if (dbc->ofsFirstUnreadEvent != ofsThisEvent || dbc->timestampFirstUnread != dbeOld.timestamp) + AddToStatus(STATUS_WARNING,TranslateT("First unread event marked wrong: fixing")); + isUnread = 1; + } } + + if (dbeOld.cbBlob>1024*1024 || dbeOld.cbBlob == 0) { + AddToStatus(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) + AddToStatus(STATUS_WARNING,TranslateT("Event not backlinked correctly: fixing")); + + dbeNew->flags = dbeOld.flags; + dbeNew->ofsPrev = ofsDestPrevEvent; + dbeNew->ofsNext = 0; + + if (dbeOld.eventType == EVENTTYPE_MESSAGE && opts.bConvertUtf) + ConvertOldEvent(dbeNew); + + if (dbePrev) + { + if (dbePrev->cbBlob == dbeNew->cbBlob && + dbePrev->ofsModuleName == dbeNew->ofsModuleName && + dbePrev->eventType == dbeNew->eventType && + (dbePrev->flags & DBEF_SENT) == (dbeNew->flags & DBEF_SENT) && + !memcmp(dbePrev->blob, dbeNew->blob, dbeNew->cbBlob) + ) { + AddToStatus(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 (opts.bCheckOnly) + { + if (!opts.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; + } + } + AddToStatus(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) + AddToStatus(STATUS_WARNING,TranslateT("Event position in chain is not correct: fixing")); + else + AddToStatus(STATUS_WARNING,TranslateT("Event position in chain is not correct: unable to fix")); + } + + // insert before FIRST + if (found == 1 && !opts.bCheckOnly) { + dbeNew->flags|=DBEF_FIRST; + dbeNew->ofsPrev = ofsContact; + dbeNew->ofsNext = dbc->ofsFirstEvent; + + ofsDestThis = WriteEvent(dbeNew); + if (!ofsDestThis) + return ERROR_HANDLE_DISK_FULL; + + if (isUnread && timestampFirstUnread >= dbeNew->timestamp) { + ofsFirstUnread = ofsDestThis; + timestampFirstUnread = dbeNew->timestamp; + } + // fix first event + WriteOfsNextToPrevious(0,dbc,ofsDestThis); + // fix next event + WriteSegment(dbeNew->ofsNext+offsetof(DBEvent,ofsPrev),&ofsDestThis,sizeof(DWORD)); + dbeTmp.flags &=~DBEF_FIRST; + WriteSegment(dbeNew->ofsNext+offsetof(DBEvent,flags),&dbeTmp.flags,sizeof(DWORD)); + } + else if (found == 2 && !opts.bCheckOnly) { + + dbeNew->ofsPrev = ofsTmp; + dbeNew->ofsNext = dbeTmp.ofsNext; + + ofsDestThis = WriteEvent(dbeNew); + if (!ofsDestThis) + return ERROR_HANDLE_DISK_FULL; + + if (isUnread && timestampFirstUnread >= dbeNew->timestamp) { + ofsFirstUnread = ofsDestThis; + timestampFirstUnread = 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; + timestampFirstUnread = dbeOld.timestamp; + } + + eventCount++; + WriteOfsNextToPrevious(ofsDestPrevEvent,dbc,ofsDestThis); + + ofsDestPrevEvent = ofsDestThis; + ofsPrevEvent = ofsThisEvent; + ofsThisEvent = dbeOld.ofsNext; + return ERROR_SUCCESS; +} diff --git a/plugins/Db3x_mmap/src/dbtool/finaltasks.cpp b/plugins/Db3x_mmap/src/dbtool/finaltasks.cpp new file mode 100644 index 0000000000..939fd680d1 --- /dev/null +++ b/plugins/Db3x_mmap/src/dbtool/finaltasks.cpp @@ -0,0 +1,78 @@ +/* +Miranda Database Tool +Copyright (C) 2001-2005 Richard Hughes + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "..\commonheaders.h" + +extern int errorCount; + +int WorkFinalTasks(int firstTime) +{ + FreeModuleChain(); + AddToStatus(STATUS_MESSAGE,TranslateT("Processing final tasks")); + dbhdr.slackSpace = 0; + if (WriteSegment(0,&dbhdr,sizeof(dbhdr)) == WS_ERROR) + return ERROR_WRITE_FAULT; + if (opts.hFile) { + CloseHandle(opts.hFile); + opts.hFile = NULL; + } + if (opts.hOutFile) { + CloseHandle(opts.hOutFile); + opts.hOutFile = NULL; + } + if (opts.pFile) { + UnmapViewOfFile(opts.pFile); + opts.pFile = NULL; + } + if (opts.hMap) { + CloseHandle(opts.hMap); + opts.hMap = NULL; + } + if (errorCount && !opts.bBackup && !opts.bCheckOnly) { + extern time_t ts; + time_t dlg_ts = time(NULL); + if (IDYES == MessageBox(NULL, + TranslateT("Errors were encountered, however you selected not to backup the original database. It is strongly recommended that you do so in case important data was omitted. Do you wish to keep a backup of the original database?"), + TranslateT("Miranda Database Tool"), MB_YESNO)) + opts.bBackup = 1; + ts += time(NULL) - dlg_ts; + } + if (opts.bBackup) { + int i; + TCHAR dbPath[MAX_PATH],dbFile[MAX_PATH]; + _tcscpy(dbPath, opts.filename); + TCHAR* str2 = _tcsrchr(dbPath, '\\'); + if (str2 != NULL) { + _tcscpy(dbFile, str2+1); + *str2 = 0; + } + else { + _tcscpy(dbFile, dbPath); + dbPath[0] = 0; + } + for(i = 1;;i++) { + if (i == 1) wsprintf(opts.backupFilename,TranslateT("%s\\Backup of %s"),dbPath,dbFile); + else wsprintf(opts.backupFilename,TranslateT("%s\\Backup (%d) of %s"),dbPath,i,dbFile); + if (_taccess(opts.backupFilename,0) == -1) break; + } + MoveFile(opts.filename,opts.backupFilename) || AddToStatus(STATUS_WARNING,TranslateT("Unable to rename original file")); + } + else if (!opts.bCheckOnly) DeleteFile(opts.filename) || AddToStatus(STATUS_WARNING,TranslateT("Unable to delete original file")); + if (!opts.bCheckOnly) MoveFile(opts.outputFilename,opts.filename) || AddToStatus(STATUS_WARNING,TranslateT("Unable to rename output file")); + return ERROR_NO_MORE_ITEMS; +} diff --git a/plugins/Db3x_mmap/src/dbtool/initialchecks.cpp b/plugins/Db3x_mmap/src/dbtool/initialchecks.cpp new file mode 100644 index 0000000000..21ccff5976 --- /dev/null +++ b/plugins/Db3x_mmap/src/dbtool/initialchecks.cpp @@ -0,0 +1,81 @@ +/* +Miranda Database Tool +Copyright (C) 2001-2005 Richard Hughes + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "..\commonheaders.h" + +extern DWORD sourceFileSize,spaceUsed; + +int WorkInitialChecks(int firstTime) +{ + DWORD bytesRead; + + sourceFileSize = GetFileSize(opts.hFile,NULL); + if (sourceFileSize == 0) { + AddToStatus(STATUS_WARNING,TranslateT("Database is newly created and has no data to process")); + AddToStatus(STATUS_SUCCESS,TranslateT("Processing completed successfully")); + return ERROR_INVALID_DATA; + } + ReadFile(opts.hFile,&dbhdr,sizeof(dbhdr),&bytesRead,NULL); + if (bytesRead")); + opts.hOutFile = INVALID_HANDLE_VALUE; + } + else { + _tcscpy(opts.outputFilename,opts.filename); + *_tcsrchr(opts.outputFilename,'.') = 0; + _tcscat(opts.outputFilename,TranslateT(" (Output).dat")); + opts.hOutFile = CreateFile(opts.outputFilename,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (opts.hOutFile == INVALID_HANDLE_VALUE) { + AddToStatus(STATUS_FATAL,TranslateT("Can't create output file (%u)"),GetLastError()); + return ERROR_ACCESS_DENIED; + } + } + + opts.hMap = CreateFileMapping(opts.hFile, NULL, opts.bAggressive?PAGE_WRITECOPY:PAGE_READONLY, 0, 0, NULL); + + if (opts.hMap) + opts.pFile = (BYTE*)MapViewOfFile(opts.hMap, opts.bAggressive?FILE_MAP_COPY:FILE_MAP_READ, 0, 0 ,0); + else { + AddToStatus(STATUS_FATAL,TranslateT("Can't create file mapping (%u)"),GetLastError()); + return ERROR_ACCESS_DENIED; + } + + if (!opts.pFile) { + AddToStatus(STATUS_FATAL,TranslateT("Can't create map view of file (%u)"),GetLastError()); + return ERROR_ACCESS_DENIED; + } + if (ReadSegment(0,&dbhdr,sizeof(dbhdr)) != ERROR_SUCCESS) return ERROR_READ_FAULT; + if (WriteSegment(0,&dbhdr,sizeof(dbhdr)) == WS_ERROR) return ERROR_HANDLE_DISK_FULL; + spaceUsed = dbhdr.ofsFileEnd-dbhdr.slackSpace; + dbhdr.ofsFileEnd = sizeof(dbhdr); + return ERROR_NO_MORE_ITEMS; +} diff --git a/plugins/Db3x_mmap/src/dbtool/modulechain.cpp b/plugins/Db3x_mmap/src/dbtool/modulechain.cpp new file mode 100644 index 0000000000..f53f63c469 --- /dev/null +++ b/plugins/Db3x_mmap/src/dbtool/modulechain.cpp @@ -0,0 +1,146 @@ +/* +Miranda Database Tool +Copyright (C) 2001-2005 Richard Hughes + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "..\commonheaders.h" + +struct ModChainEntry { + DWORD ofsOld,ofsNew; + int size; + char name[257]; +} static *modChain = NULL; +static int modChainCount; +static DWORD ofsCurrent; +static int phase,iCurrentModName; +static DWORD ofsLast; +static int last_mod = 0; + +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*)_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;iofsFirstSettings; + 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*)_alloca(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: skipping"),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; +} diff --git a/plugins/Db3x_mmap/src/dbtool/user.cpp b/plugins/Db3x_mmap/src/dbtool/user.cpp new file mode 100644 index 0000000000..d61add09d4 --- /dev/null +++ b/plugins/Db3x_mmap/src/dbtool/user.cpp @@ -0,0 +1,71 @@ +/* +Miranda Database Tool +Copyright (C) 2001-2005 Richard Hughes + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "..\commonheaders.h" + +static DBContact user; +static int phase; +static DWORD ofsUser; + +int WorkSettingsChain(DWORD ofsContact,DBContact *dbc,int firstTime); +int WorkEventChain(DWORD ofsContact,DBContact *dbc,int firstTime); + +int WorkUser(int firstTime) +{ + int first = 0; + + if (firstTime) { + AddToStatus(STATUS_MESSAGE,TranslateT("Processing user data")); + if (!SignatureValid(dbhdr.ofsUser,DBCONTACT_SIGNATURE)) { + AddToStatus(STATUS_ERROR,TranslateT("User corrupted, this could cause major problems")); + return ERROR_NO_MORE_ITEMS; + } + if (ReadSegment(dbhdr.ofsUser,&user,sizeof(DBContact)) != ERROR_SUCCESS) + return ERROR_NO_MORE_ITEMS; + if (user.ofsNext) { + AddToStatus(STATUS_WARNING,TranslateT("More than one user contact: keeping only first")); + user.ofsNext = 0; + } + if ((ofsUser = WriteSegment(WSOFS_END,&user,sizeof(DBContact))) == WS_ERROR) + return ERROR_HANDLE_DISK_FULL; + dbhdr.ofsUser = ofsUser; + phase = 0; + first = 1; + } + switch(phase) { + int ret; + + case 0: + ret = WorkSettingsChain(ofsUser,&user,first); + if (ret == ERROR_NO_MORE_ITEMS) { + phase++; first = 1; + } + else if (ret) return ret; + else break; + case 1: + ret = WorkEventChain(ofsUser,&user,first); + if (ret == ERROR_NO_MORE_ITEMS) { + if (WriteSegment(ofsUser,&user,sizeof(DBContact)) == WS_ERROR) + return ERROR_HANDLE_DISK_FULL; + return ERROR_NO_MORE_ITEMS; + } + else if (ret) return ret; + break; + } + return ERROR_SUCCESS; +} \ No newline at end of file -- cgit v1.2.3