/* 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. */ #pragma once #include #include #include "stdint.h" #include "sigslot.h" class CFileAccess { public: static const uint8_t cJournalSignature[20]; CFileAccess(const TCHAR* FileName); virtual ~CFileAccess(); uint32_t Read(void* Buf, uint32_t Source, uint32_t Size) { return _Read(Buf, Source, Size); }; bool Write(void* Buf, uint32_t Dest, uint32_t Size) { if (m_Journal.Use) { DWORD written; TJournalEntry * data = reinterpret_cast(m_Journal.Buffer + m_Journal.BufUse); data->Signature = 'writ'; data->Address = Dest; data->Size = Size; m_Journal.BufUse += 12; if (Size + m_Journal.BufUse < sizeof(m_Journal.Buffer) - 12) // one journal header has always to fit in { memcpy(m_Journal.Buffer + m_Journal.BufUse, Buf, Size); m_Journal.BufUse += Size; } else { WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse, &written, NULL); WriteFile(m_Journal.hFile, Buf, Size, &written, NULL); m_Journal.BufUse = 0; } } else { _Write(Buf, Dest, Size); } return true; }; void Invalidate(uint32_t Dest, uint32_t Size) { if (m_Journal.Use) { DWORD written; TJournalEntry * data = reinterpret_cast(m_Journal.Buffer + m_Journal.BufUse); data->Signature = 'inva'; data->Address = Dest; data->Size = Size; m_Journal.BufUse += 12; if (m_Journal.BufUse > sizeof(m_Journal.Buffer) - 12) { WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse, &written, NULL); m_Journal.BufUse = 0; } } else { _Invalidate(Dest, Size); } }; void Flush() { if (m_Journal.Use) { if (m_Journal.BufUse) { DWORD written; WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse, &written, NULL); m_Journal.BufUse = 0; } FlushFileBuffers(m_Journal.hFile); } else { _Flush(); } }; void UseJournal(bool UseIt) { m_Journal.Use = UseIt; }; void CompleteTransaction() { if (m_Size != m_LastSize) { m_sigFileSizeChanged.emit(this, m_Size); m_LastSize = m_Size; } }; void CloseTransaction() { if (m_Journal.Use) { DWORD written; TJournalEntry * data = reinterpret_cast(m_Journal.Buffer + m_Journal.BufUse); data->Signature = 'fini'; data->Address = 0; data->Size = m_Size; WriteFile(m_Journal.hFile, m_Journal.Buffer, m_Journal.BufUse + 12, &written, NULL); m_Journal.BufUse = 0; } }; void CleanJournal(); uint32_t Size(uint32_t NewSize); uint32_t Size() { return m_Size; }; void ReadOnly(bool ReadOnly) { m_ReadOnly = ReadOnly; }; bool ReadOnly() { return m_ReadOnly; }; typedef sigslot::signal2 TOnFileSizeChanged; TOnFileSizeChanged & sigFileSizeChanged() { return m_sigFileSizeChanged; }; protected: TCHAR* m_FileName; struct { bool Use; TCHAR* FileName; HANDLE hFile; uint8_t Buffer[4096]; uint32_t BufUse; } m_Journal; uint32_t m_Size; uint32_t m_AllocSize; uint32_t m_AllocGranularity; uint32_t m_MinAllocGranularity; uint32_t m_MaxAllocGranularity; uint32_t m_LastAllocTime; bool m_ReadOnly; uint32_t m_LastSize; TOnFileSizeChanged m_sigFileSizeChanged; virtual uint32_t _Read(void* Buf, uint32_t Source, uint32_t Size) = 0; virtual uint32_t _Write(void* Buf, uint32_t Dest, uint32_t Size) = 0; virtual void _Invalidate(uint32_t Dest, uint32_t Size) = 0; virtual uint32_t _SetSize(uint32_t Size) = 0; virtual void _Flush() = 0; #pragma pack (push, 1) typedef struct TJournalEntry { uint32_t Signature; uint32_t Address; uint32_t Size; } TJournalEntry; #pragma pack (pop) void InitJournal(); void ProcessJournal(); };