diff options
Diffstat (limited to 'plugins/Dbx_tree/src/FileAccess.cpp')
-rw-r--r-- | plugins/Dbx_tree/src/FileAccess.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/plugins/Dbx_tree/src/FileAccess.cpp b/plugins/Dbx_tree/src/FileAccess.cpp new file mode 100644 index 0000000000..a0aa85aecb --- /dev/null +++ b/plugins/Dbx_tree/src/FileAccess.cpp @@ -0,0 +1,299 @@ +/*
+
+dbx_tree: tree database driver for Miranda IM
+
+Copyright 2007-2010 Michael "Protogenes" Kunz,
+
+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 "FileAccess.h"
+#include <vector>
+#ifndef _MSC_VER
+#include "savestrings_gcc.h"
+#define _time32 time
+#endif
+#include "Logger.h"
+
+const uint8_t CFileAccess::cJournalSignature[20] = "Miranda IM Journal!";
+
+CFileAccess::CFileAccess(const TCHAR* FileName)
+{
+ m_FileName = new TCHAR[_tcslen(FileName) + 1];
+ m_Journal.FileName = new TCHAR[_tcslen(FileName) + 5];
+ _tcscpy_s(m_FileName, _tcslen(FileName) + 1, FileName);
+ _tcscpy_s(m_Journal.FileName, _tcslen(FileName) + 5, FileName);
+ _tcscat_s(m_Journal.FileName, _tcslen(FileName) + 5, _T(".jrn"));
+
+ m_ReadOnly = false;
+ m_LastSize = 0;
+ m_Size = 0;
+ m_Journal.Use = false;
+ m_Journal.hFile = 0;
+ m_Journal.BufUse = 0;
+
+ m_LastAllocTime = _time32(NULL);
+}
+
+CFileAccess::~CFileAccess()
+{
+ CloseHandle(m_Journal.hFile);
+ DeleteFile(m_Journal.FileName);
+
+ delete [] m_FileName;
+ delete [] m_Journal.FileName;
+}
+
+uint32_t CFileAccess::Size(uint32_t NewSize)
+{
+ m_Size = NewSize;
+ if (!m_Journal.Use)
+ {
+ NewSize = (NewSize + m_AllocGranularity - 1) & ~(m_AllocGranularity - 1);
+
+ if (NewSize == 0)
+ NewSize = m_AllocGranularity;
+
+ if (NewSize != m_AllocSize)
+ {
+ m_AllocSize = _SetSize(NewSize);
+
+ // adapt Alloc Granularity
+ uint32_t t = _time32(NULL);
+ uint32_t d = t - m_LastAllocTime;
+ m_LastAllocTime = t;
+
+ if (d < 30) // increase alloc stepping
+ {
+ if (m_AllocGranularity < m_MaxAllocGranularity)
+ m_AllocGranularity = m_AllocGranularity << 1;
+ } else if (d > 120) // decrease alloc stepping
+ {
+ if (m_AllocGranularity > m_MinAllocGranularity)
+ m_AllocGranularity = m_AllocGranularity >> 1;
+ }
+ }
+ }
+ return NewSize;
+}
+
+
+void CFileAccess::CleanJournal()
+{
+ SetFilePointer(m_Journal.hFile, 0, NULL, FILE_BEGIN);
+ SetEndOfFile(m_Journal.hFile);
+
+ DWORD written;
+ WriteFile(m_Journal.hFile, cJournalSignature, sizeof(cJournalSignature), &written, NULL);
+}
+
+void CFileAccess::ProcessJournal()
+{
+ uint32_t filesize = GetFileSize(m_Journal.hFile, NULL) - sizeof(cJournalSignature);
+ SetFilePointer(m_Journal.hFile, sizeof(cJournalSignature), NULL, FILE_BEGIN);
+
+ uint8_t* buf = (uint8_t*)malloc(filesize);
+ TJournalEntry* e = (TJournalEntry*)buf;
+ DWORD read = 0;
+ if (!ReadFile(m_Journal.hFile, buf, filesize, &read, NULL) || (read != filesize))
+ {
+ free(buf);
+ LOGSYS(logCRITICAL, _T("Couldn't flush the journal because ReadFile failed!"));
+ return;
+ }
+
+ m_Journal.Use = false;
+ std::vector<TJournalEntry*> currentops;
+
+ while (filesize >= sizeof(TJournalEntry))
+ {
+ switch (e->Signature)
+ {
+ case 'fini':
+ {
+ Size(e->Size);
+
+ std::vector<TJournalEntry*>::iterator i = currentops.begin();
+ while (i != currentops.end())
+ {
+ switch ((*i)->Signature)
+ {
+ case 'writ':
+ {
+ if ((*i)->Address + (*i)->Size <= m_AllocSize)
+ {
+ _Write(*i + 1, (*i)->Address, (*i)->Size);
+ } else if ((*i)->Address < m_AllocSize)
+ {
+ _Write(*i + 1, (*i)->Address, m_AllocSize - (*i)->Address);
+ }
+ } break;
+ case 'inva':
+ {
+ if ((*i)->Address + (*i)->Size <= m_AllocSize)
+ {
+ _Invalidate((*i)->Address, (*i)->Size);
+ } else if ((*i)->Address < m_AllocSize)
+ {
+ _Invalidate((*i)->Address, m_AllocSize - (*i)->Address);
+ }
+ } break;
+ }
+ ++i;
+ }
+ currentops.clear();
+
+ e++;
+ filesize = filesize - sizeof(TJournalEntry);
+ } break;
+ case 'writ':
+ {
+ if (filesize < sizeof(e) + e->Size)
+ {
+ filesize = 0;
+ } else {
+ currentops.push_back(e);
+ filesize = filesize - sizeof(TJournalEntry) - e->Size;
+ e = (TJournalEntry*)((uint8_t*)e + sizeof(TJournalEntry) + e->Size);
+ }
+ } break;
+ case 'inva':
+ {
+ if (filesize < sizeof(e))
+ {
+ filesize = 0;
+ } else {
+ currentops.push_back(e);
+ e++;
+ filesize = filesize - sizeof(TJournalEntry);
+ }
+ } break;
+ default:
+ {
+ filesize = 0;
+ if (currentops.size())
+ LOG(logWARNING, _T("Your database journal wasn't completely written to disk."));
+ } break;
+ }
+ }
+
+ _Flush();
+
+ CleanJournal();
+
+ free(buf);
+ m_Journal.Use = true;
+}
+
+void CFileAccess::InitJournal()
+{
+ m_Journal.hFile = CreateFile(m_Journal.FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (m_Journal.hFile == INVALID_HANDLE_VALUE)
+ {
+ LOGSYS(logCRITICAL, _T("CreateFile failed on Journal %s"), m_Journal.FileName);
+ return;
+ }
+
+ uint8_t h[sizeof(cJournalSignature)];
+ DWORD read;
+ if (ReadFile(m_Journal.hFile, &h, sizeof(h), &read, NULL) && (read == sizeof(h)) && (0 == memcmp(h, cJournalSignature, sizeof(h))))
+ {
+ TCHAR * bckname = new TCHAR[_tcslen(m_FileName) + 12];
+ _tcscpy_s(bckname, _tcslen(m_FileName) + 12, m_FileName);
+ _tcscat_s(bckname, _tcslen(m_FileName) + 12, _T(".autobackup"));
+
+ TCHAR * bckjrnname = new TCHAR[_tcslen(m_Journal.FileName) + 12];
+ _tcscpy_s(bckjrnname, _tcslen(m_Journal.FileName) + 12, m_Journal.FileName);
+ _tcscat_s(bckjrnname, _tcslen(m_Journal.FileName) + 12, _T(".autobackup"));
+
+ char buf[4096];
+ HANDLE hfilebackup = CreateFile(bckname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (hfilebackup)
+ {
+ uint32_t i = 0;
+ while (i + sizeof(buf) <= m_AllocSize)
+ {
+ DWORD w;
+ _Read(buf, i, sizeof(buf));
+ i += sizeof(buf);
+ WriteFile(hfilebackup, buf, sizeof(buf), &w, NULL);
+ }
+ if (i < m_AllocSize)
+ {
+ DWORD w;
+ _Read(buf, i, m_AllocSize - i);
+ WriteFile(hfilebackup, buf, m_AllocSize - i, &w, NULL);
+ }
+
+ CloseHandle(hfilebackup);
+ }
+
+ HANDLE hjrnfilebackup = CreateFile(bckjrnname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
+ if (hjrnfilebackup)
+ {
+ uint32_t i = 0;
+
+ uint32_t filesize = GetFileSize(m_Journal.hFile, NULL);
+ SetFilePointer(m_Journal.hFile, 0, NULL, FILE_BEGIN);
+
+ while (i + sizeof(buf) <= filesize)
+ {
+ DWORD w, r;
+ ReadFile(m_Journal.hFile, buf, sizeof(buf), &r, NULL);
+ i += sizeof(buf);
+ WriteFile(hjrnfilebackup, buf, sizeof(buf), &w, NULL);
+ }
+ if (i < filesize)
+ {
+ DWORD w, r;
+ ReadFile(m_Journal.hFile, buf, filesize - i, &r, NULL);
+ WriteFile(hjrnfilebackup, buf, filesize - i, &w, NULL);
+ }
+ CloseHandle(hjrnfilebackup);
+ }
+
+ TCHAR* path = bckname;
+ TCHAR* fn = _tcsrchr(m_Journal.FileName, _T('\\'));
+ TCHAR* bfn = _tcsrchr(bckname, _T('\\'));
+ TCHAR* jrn = _tcsrchr(bckjrnname, _T('\\'));
+ if (bfn) // truncate path var
+ *bfn = 0;
+
+ if (hfilebackup || hjrnfilebackup)
+ {
+ LOG(logWARNING,
+ _T("Journal \"%s\" was found on start.\nBackup \"%s\"%s created and backup \"%s\"%s created.\nYou may delete these file(s) after successful start from \"%s\"."),
+ fn?fn+1:m_Journal.FileName,
+ bfn?bfn+1:bckname, (hfilebackup!=INVALID_HANDLE_VALUE)?_T(" was successfully"):_T(" could not be"),
+ jrn?jrn+1:bckjrnname, (hjrnfilebackup!=INVALID_HANDLE_VALUE)?_T(" was successfully"):_T(" could not be"),
+ path);
+ } else {
+ LOG(logWARNING,
+ _T("Journal \"%s\" was found on start.\nBackups \"%s\"and \"%s\" could not be created in \"%s\"."),
+ fn?fn+1:m_Journal.FileName,
+ bfn?bfn+1:bckname,
+ jrn?jrn+1:bckjrnname,
+ path);
+ }
+
+ delete [] bckname;
+ delete [] bckjrnname;
+
+ ProcessJournal();
+ }
+
+ CleanJournal();
+}
|