From 7aff1e4cb053394db57c2814d5fe1e6493e0cc75 Mon Sep 17 00:00:00 2001 From: watcherhd Date: Sat, 26 Nov 2011 14:19:43 +0000 Subject: Project folders rename part 2 git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@214 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- Dbx_tree/BlockManager.cpp | 965 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 965 insertions(+) create mode 100644 Dbx_tree/BlockManager.cpp (limited to 'Dbx_tree/BlockManager.cpp') diff --git a/Dbx_tree/BlockManager.cpp b/Dbx_tree/BlockManager.cpp new file mode 100644 index 0000000..3be5d80 --- /dev/null +++ b/Dbx_tree/BlockManager.cpp @@ -0,0 +1,965 @@ +/* + +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 "BlockManager.h" +#include "Logger.h" + +CBlockManager::CBlockManager( + CFileAccess & FileAccess, + CEncryptionManager & EncryptionManager + ) +: m_BlockSync(), + m_FileAccess(FileAccess), + m_EncryptionManager(EncryptionManager), + m_BlockTable(1024), + m_FreeBlocks() +{ + m_Optimize.Thread = NULL; + m_Optimize.Source = 0; + m_Optimize.Dest = 0; + + m_CacheInfo.Growth = 0; + m_CacheInfo.Size = 0; + m_CacheInfo.LastPurge = time(NULL); + + m_PendingHead = NULL; + m_PendingTail = NULL; + m_PendingLast = NULL; + m_LastFlush = time(NULL); + m_BytesPending = 20; + m_FirstFreeIndex = 0; + + m_SaveMode = true; + m_ReadOnly = m_FileAccess.ReadOnly(); + + memset(m_Cache, 0, sizeof(m_Cache)); +} + +CBlockManager::~CBlockManager() +{ + m_BlockSync.BeginWrite(); + if (m_Optimize.Thread) + { + m_Optimize.Thread->FreeOnTerminate(false); + m_Optimize.Thread->Terminate(); + + m_BlockSync.EndWrite(); + m_Optimize.Thread->WaitFor(); + + delete m_Optimize.Thread; + } else { + m_BlockSync.EndWrite(); + } + + _PendingFlush(true); + + for (uint32_t buddy = 0; buddy < cCacheBuddyCount; buddy++) + { + TCacheEntry * i = m_Cache[buddy]; + while (i) + { + free(i->Cache); + + TCacheEntry * tmp = i; + i = i->Next; + free(tmp); + } + } +} + +// Optimize File Size +void CBlockManager::ExecuteOptimize() +{ /* + TBlockHeadFree h = {0,0}; + uint8_t * buf = (uint8_t*)malloc(1 << 18); // 256kb + uint32_t bufuse = 0; + uint32_t bufsize = 1 << 18; + uint32_t lastflush = 0; + + { + int i = 0; + while (!m_Optimize.Thread->Terminated() && (i < 600)) + { + ++i; + Sleep(100); // wait for Miranda to start + } + } + + TransactionBeginWrite(); + + while (!m_Optimize.Thread->Terminated() && (m_Optimize.Source < m_FileAccess.Size()) && !m_ReadOnly) + { + m_FileAccess.Read(&h, m_Optimize.Source, sizeof(h)); + if (h.ID == cFreeBlockID) + { + _RemoveFreeBlock(m_Optimize.Source, h.Size); + + m_Optimize.Source += h.Size; + } else { + + if (bufsize < bufuse + h.Size) + { + buf = (uint8_t*)realloc(buf, bufuse + h.Size); + bufsize = bufuse + h.Size; + } + m_FileAccess.Read(buf + bufuse, m_Optimize.Source, h.Size); + + m_BlockTable[h.ID >> 2].Addr = (m_Optimize.Dest + bufuse) >> 2; + + m_Optimize.Source += h.Size; + bufuse += h.Size; + } + + if ((m_BlockSync.Waiting() > 0) + || (bufuse + 1024 >= bufsize) + || (m_Optimize.Source >= m_FileAccess.Size())) // buffer is nearly full or EOF + { + if (m_Optimize.Dest != m_Optimize.Source) // move blocks + { + TBlockHeadFree h = {cFreeBlockID, m_Optimize.Source - m_Optimize.Dest}; + TBlockTailFree t = {m_Optimize.Source - m_Optimize.Dest, cFreeBlockID}; + + m_FileAccess.Write(buf, m_Optimize.Dest, bufuse); + + m_FileAccess.Write(&h, m_Optimize.Dest + bufuse, sizeof(h)); + m_FileAccess.Invalidate(m_Optimize.Dest + bufuse + sizeof(h), m_Optimize.Source - m_Optimize.Dest - bufuse - sizeof(h) - sizeof(t)); + m_FileAccess.Write(&t, m_Optimize.Dest + bufuse - sizeof(t), sizeof(t)); + + if (m_SaveMode) + { + m_FileAccess.CloseTransaction(); + m_FileAccess.Flush(); + m_FileAccess.UseJournal(false); + + m_FileAccess.Write(buf, m_Optimize.Dest, bufuse); + + m_FileAccess.Write(&h, m_Optimize.Dest + bufuse, sizeof(h)); + m_FileAccess.Invalidate(m_Optimize.Dest + bufuse + sizeof(h), m_Optimize.Source - m_Optimize.Dest - bufuse - sizeof(h) - sizeof(t)); + m_FileAccess.Write(&t, m_Optimize.Dest + bufuse - sizeof(t), sizeof(t)); + + m_FileAccess.Flush(); + m_FileAccess.CleanJournal(); + m_FileAccess.UseJournal(true); + } + + m_Optimize.Dest += bufuse; + bufuse = 0; + } + + if (m_BlockSync.Waiting() > 0) + { + unsigned int w = m_BlockSync.Waiting(); + m_BlockSync.EndWrite(); + Sleep(w * 64 + 1); + m_BlockSync.BeginWrite(); + m_FileAccess.UseJournal(m_SaveMode); + } + } + } + + if (m_Optimize.Source >= m_FileAccess.Size()) + m_FileAccess.Size(m_Optimize.Dest); + + m_Optimize.Thread = NULL; + m_Optimize.Source = 0; + m_Optimize.Dest = 0; + if (m_SaveMode) + TransactionEndWrite(); + else + m_BlockSync.EndWrite(); + + free(buf); */ + + m_Optimize.Thread = NULL; +} + +inline void CBlockManager::_PendingAdd(uint32_t BlockID, uint32_t Addr, uint32_t Size, TCacheEntry * Cache) +{ + TPendingOperation * p = NULL; + if (BlockID == cFreeBlockID) + { + p = (TPendingOperation*)malloc(sizeof(TPendingOperation)); + + p->BlockID = cFreeBlockID; + p->Addr = Addr; + p->Size = Size; + p->CacheEntry = NULL; + p->EncryptionBuffer = NULL; + + m_BytesPending += 24 + sizeof(TBlockHeadFree) + sizeof(TBlockTailFree); + if (Addr & cPendingInvalidate) + m_BytesPending += 12; + + } else { + if (Cache->Pending) + { + p = Cache->Pending; + _PendingRemove(Cache->Pending, false); + } else { + p = (TPendingOperation*)malloc(sizeof(TPendingOperation)); + } + + p->BlockID = BlockID; + p->Addr = Addr; + p->Size = Size; + p->CacheEntry = Cache; + p->EncryptionBuffer = NULL; + + m_BytesPending += 12 + Size; + + Cache->Pending = p; + } + + p->Next = NULL; + p->Prev = m_PendingTail; + if (m_PendingTail) + m_PendingTail->Next = p; + + m_PendingTail = p; + if (!m_PendingHead) + m_PendingHead = p; +} + +inline void CBlockManager::_PendingRemove(TPendingOperation * Pending, bool Free) +{ + if (Pending->Prev) + Pending->Prev->Next = Pending->Next; + else + m_PendingHead = Pending->Next; + + if (Pending->Next) + Pending->Next->Prev = Pending->Prev; + else + m_PendingTail = Pending->Prev; + + if (Pending->EncryptionBuffer) + free(Pending->EncryptionBuffer); + + if (m_PendingLast == Pending) + m_PendingLast = Pending->Prev; + + Pending->CacheEntry->Pending = NULL; + if (Free) + free(Pending); +} + +inline void CBlockManager::_PendingFlush(bool FullFlush) +{ + TPendingOperation * i = NULL; + + if (m_ReadOnly) + return; + + if (FullFlush) + { + if (m_SaveMode) + { + _PendingFlush(false); // write to journal + m_FileAccess.Flush(); + m_FileAccess.UseJournal(false); + m_FileAccess.Size(m_FileAccess.Size()); // resize real file + } else { + m_FileAccess.UseJournal(false); + } + + i = m_PendingHead; + } else if (m_PendingLast) + { + i = m_PendingLast->Next; + m_FileAccess.UseJournal(m_SaveMode); + } else { + i = m_PendingHead; + m_FileAccess.UseJournal(m_SaveMode); + } + + while (i) + { + if (i->BlockID == cFreeBlockID) + { + uint32_t addr = i->Addr & ~cPendingInvalidate; + if (addr + i->Size <= m_FileAccess.Size()) + { + TBlockHeadFree h = {cFreeBlockID, i->Size}; + TBlockTailFree t = {i->Size, cFreeBlockID}; + + m_FileAccess.Write(&h, addr, sizeof(h)); + if (i->Addr & cPendingInvalidate) + m_FileAccess.Invalidate(addr + sizeof(h), i->Size - sizeof(h) - sizeof(t)); + m_FileAccess.Write(&t, addr + i->Size - sizeof(t), sizeof(t)); + } + + } else { + + if (i->BlockID && !i->EncryptionBuffer && m_EncryptionManager.IsEncrypted(i->BlockID)) + { + i->EncryptionBuffer = (TBlockHeadOcc*) malloc(i->Size); + memcpy(i->EncryptionBuffer, i->CacheEntry->Cache, i->Size); + m_EncryptionManager.Encrypt(i->EncryptionBuffer + 1, i->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc), i->BlockID, 0); + } + + if (i->EncryptionBuffer) + { + m_FileAccess.Write(i->EncryptionBuffer, i->Addr, i->Size); + } else { + m_FileAccess.Write(i->CacheEntry->Cache, i->Addr, i->Size); + } + } + + i = i->Next; + } // while + + if (FullFlush) + { + m_FileAccess.Flush(); + if (m_SaveMode) + m_FileAccess.CleanJournal(); + + m_BytesPending = 20; + m_LastFlush = time(NULL); + + i = m_PendingHead; + while (i) + { + if (i->EncryptionBuffer) + free(i->EncryptionBuffer); + + if (i->CacheEntry) + i->CacheEntry->Pending = NULL; + + TPendingOperation * tmp = i; + i = i->Next; + free(tmp); + } + m_PendingHead = NULL; + m_PendingTail = NULL; + m_PendingLast = NULL; + } else { + m_PendingLast = m_PendingTail; + m_FileAccess.CloseTransaction(); + } +} + +inline CBlockManager::TCacheEntry * CBlockManager::_CacheInsert(uint32_t Idx, TBlockHeadOcc * Cache, bool Virtual) +{ + TCacheEntry * res; + uint32_t myidx = ROR_32(Idx, cCacheBuddyBits); + + res = (TCacheEntry *)malloc(sizeof(TCacheEntry)); + res->Cache = Cache; + res->Pending = NULL; + res->Idx = myidx; + res->Forced = Virtual; + + TCacheEntry * volatile * last = &m_Cache[Idx % cCacheBuddyCount]; + TCacheEntry * i; + do { + i = *last; + + while (i && (i->Idx < myidx)) + { + last = &i->Next; + i = i->Next; + } + + if (i && (i->Idx == myidx)) + { + free(res); + free(Cache); + + i->LastUse = time(NULL) >> 2; + return i; + } + + res->Next = i; + + } while (i != CMPXCHG_Ptr(*last, res, i) ); + + res->LastUse = time(NULL) >> 2; + + m_BlockTable[Idx].InCache = true; + if (!Virtual) + XADD_32(m_CacheInfo.Growth, res->Cache->Size); + + return res; +} + +inline CBlockManager::TCacheEntry * CBlockManager::_CacheFind(uint32_t Idx) +{ + TCacheEntry * i = m_Cache[Idx % cCacheBuddyCount]; + uint32_t myidx = ROR_32(Idx, cCacheBuddyBits); + while (i && (i->Idx < myidx)) + i = i->Next; + + if (i && (i->Idx == myidx)) + return i; + else + return NULL; +} + +inline void CBlockManager::_CacheErase(uint32_t Idx) +{ + TCacheEntry * i = m_Cache[Idx % cCacheBuddyCount]; + TCacheEntry * volatile * l = &m_Cache[Idx % cCacheBuddyCount]; + + uint32_t myidx = ROR_32(Idx, cCacheBuddyBits); + + while (i->Idx < myidx) + { + l = &i->Next; + i = i->Next; + } + *l = i->Next; + + if (i->Cache) + free(i->Cache); + free(i); +} + +inline void CBlockManager::_CachePurge() +{ + _PendingFlush(true); + + uint32_t ts = time(NULL); + if (m_CacheInfo.Size + m_CacheInfo.Growth > cCachePurgeSize) { + ts = ts - (ts - m_CacheInfo.LastPurge) * cCachePurgeSize / (m_CacheInfo.Size + 2 * m_CacheInfo.Growth); + } else if (m_CacheInfo.Growth > m_CacheInfo.Size) + { + ts = ts - (ts - m_CacheInfo.LastPurge) * m_CacheInfo.Size / m_CacheInfo.Growth; + } else if (m_CacheInfo.Size > m_CacheInfo.Growth) + { + ts = ts - (ts - m_CacheInfo.LastPurge) * m_CacheInfo.Growth / m_CacheInfo.Size; + } else { + ts = m_CacheInfo.LastPurge; + } + + m_CacheInfo.Size += m_CacheInfo.Growth; + m_CacheInfo.Growth = 0; + m_CacheInfo.LastPurge = time(NULL); + + for (uint32_t buddy = 0; buddy < cCacheBuddyCount; buddy++) + { + TCacheEntry * i = m_Cache[buddy]; + TCacheEntry * volatile * l = &m_Cache[buddy]; + + while (i) + { + if (!i->Forced && !i->KeepInCache && i->Idx && ((i->LastUse << 2) < ts)) + { + uint32_t idx = ROL_32(i->Idx, cCacheBuddyBits); + m_CacheInfo.Size -= i->Cache->Size; + m_BlockTable[idx].InCache = false; + free(i->Cache); + + *l = i->Next; + TCacheEntry * tmp = i; + i = i->Next; + free(tmp); + + } else { + l = &i->Next; + i = i->Next; + } + } + } +} + +inline uint32_t CBlockManager::_GetAvailableIndex() +{ + uint32_t id; + if (m_FirstFreeIndex) + { + id = m_FirstFreeIndex; + m_FirstFreeIndex = m_BlockTable[id].Addr; + TBlockTableEntry b = {false, false, 0}; + m_BlockTable[id] = b; + } else { + id = static_cast(m_BlockTable.size()); + if (id > (1 << 12)) + m_BlockTable.resize(id + (1 << 12)); + else + m_BlockTable.resize(id * 2); + + for (uint32_t i = static_cast(m_BlockTable.size() - 1); i > id; --i) + { + TBlockTableEntry b = {true, true, m_FirstFreeIndex}; + m_BlockTable[i] = b; + m_FirstFreeIndex = i; + } + } + return id; +} + +inline void CBlockManager::_InsertFreeBlock(uint32_t Addr, uint32_t Size, bool InvalidateData, bool Reuse) +{ + if (Addr + Size == m_FileAccess.Size()) + { + if (Reuse) // in FindFreePosition we would want to use that block + m_FileAccess.Size(Addr); + } else { + + if (Reuse) + m_FreeBlocks.insert(std::make_pair(Size, Addr)); + + if (!m_ReadOnly) + _PendingAdd(cFreeBlockID, InvalidateData ? Addr | cPendingInvalidate : Addr, Size, NULL); + + } +} + +inline void CBlockManager::_RemoveFreeBlock(uint32_t Addr, uint32_t Size) +{ + TFreeBlockMap::iterator i = m_FreeBlocks.find(Size); + while ((i != m_FreeBlocks.end()) && (i->first == Size)) + { + if (i->second == Addr) + { + m_FreeBlocks.erase(i); + i = m_FreeBlocks.end(); + } else { + ++i; + } + } +} + +inline uint32_t CBlockManager::_FindFreePosition(uint32_t Size) +{ + // try to find free block + TFreeBlockMap::iterator f; + TFreeBlockMap::iterator e = m_FreeBlocks.end(); + + if (m_FreeBlocks.size()) + { + f = m_FreeBlocks.find(Size); + if (f == e) + { + if (m_FreeBlocks.rbegin()->first > Size * 2) + { + f = m_FreeBlocks.end(); + --f; + } + } + } else { + f = e; + } + + uint32_t addr = 0; + + if (f == e) // no block found - expand file + { + addr = m_FileAccess.Size(); + m_FileAccess.Size(addr + Size); + + } else { + addr = f->second; + + if (f->first != Size) + { + _InsertFreeBlock(addr + Size, f->first - Size, false, true); + } + _InsertFreeBlock(addr, Size, false, false); + + m_FreeBlocks.erase(f); + } + + return addr; +} + +inline bool CBlockManager::_InitOperation(uint32_t BlockID, uint32_t & Addr, TCacheEntry * & Cache) +{ + if (!BlockID || (BlockID & 3) || ((BlockID >> 2) >= m_BlockTable.size())) + return false; + + uint32_t idx = BlockID >> 2; + TBlockTableEntry dat = m_BlockTable[idx]; + + if (dat.Deleted) // deleted or FreeIDList item + return false; + + Addr = dat.Addr << 2; + if (dat.InCache) + { + Cache = _CacheFind(idx); + } else if (Addr) + { + TBlockHeadOcc h; + + m_FileAccess.Read(&h, Addr, sizeof(h)); + + TBlockHeadOcc * block = (TBlockHeadOcc *) malloc(h.Size); + m_FileAccess.Read(block, Addr, h.Size); + + m_EncryptionManager.Decrypt(block + 1, h.Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc), BlockID, 0); + + Cache = _CacheInsert(idx, block, false); + } else { + return false; + } + + return Cache != NULL; +} + +inline void CBlockManager::_UpdateBlock(uint32_t BlockID, TCacheEntry * CacheEntry, uint32_t Addr) +{ + CacheEntry->KeepInCache = m_ReadOnly; + + if (!CacheEntry->Forced) + { + if (!m_ReadOnly) + _PendingAdd(BlockID, Addr, CacheEntry->Cache->Size, CacheEntry); + } +} + + +uint32_t CBlockManager::ScanFile(uint32_t FirstBlockStart, uint32_t HeaderSignature, uint32_t FileSize) +{ + TBlockHeadOcc h, lasth = {0, 0, 0}; + uint32_t p; + uint32_t res = 0; + bool invalidateblock = false; + + p = FirstBlockStart; + m_FirstBlockStart = FirstBlockStart; + m_Optimize.Source = 0; + m_Optimize.Dest = 0; + + { // insert header cache element + void * header = malloc(FirstBlockStart); + m_FileAccess.Read(header, 0, FirstBlockStart); + _CacheInsert(0, (TBlockHeadOcc*)header, false); + } + + TransactionBeginWrite(); + + while (p < FileSize) + { + m_FileAccess.Read(&h, p, sizeof(h)); + if (CLogger::Instance().Level() >= CLogger::logERROR || !h.Size) + { + LOG(logCRITICAL, _T("Block-structure of file is corrupt!")); + return 0; + } + + if (h.ID == cFreeBlockID) + { + if (m_Optimize.Dest == 0) + m_Optimize.Dest = p; + + if (lasth.ID == cFreeBlockID) + { + lasth.Size += h.Size; + invalidateblock = true; + } else { + lasth = h; + } + + } else { + + if (lasth.ID == cFreeBlockID) + { + if (m_Optimize.Source == 0) + m_Optimize.Source = p; + + _InsertFreeBlock(p - lasth.Size, lasth.Size, invalidateblock, true); + } + lasth = h; + invalidateblock = false; + + while ((h.ID >> 2) >= m_BlockTable.size()) + m_BlockTable.resize(m_BlockTable.size() << 1); + + m_BlockTable[h.ID >> 2].Addr = p >> 2; + + if (h.Signature == HeaderSignature) + res = h.ID; + } + + p = p + h.Size; + } + + m_FirstFreeIndex = 0; + for (uint32_t i = static_cast(m_BlockTable.size() - 1); i > 0; --i) + { + if (m_BlockTable[i].Addr == 0) + { + TBlockTableEntry b = {true, true, m_FirstFreeIndex}; + m_BlockTable[i] = b; + m_FirstFreeIndex = i; + } + } + + TransactionEndWrite(); + + if (m_Optimize.Source && !m_FileAccess.ReadOnly()) + { + m_Optimize.Thread = new COptimizeThread(*this); + m_Optimize.Thread->Priority(CThread::tpLowest); + m_Optimize.Thread->FreeOnTerminate(true); + m_Optimize.Thread->Resume(); + } + + return res; +} + +void * CBlockManager::_CreateBlock(uint32_t & BlockID, const uint32_t Signature, uint32_t Size) +{ + uint32_t idx = _GetAvailableIndex(); + BlockID = idx << 2; + + Size = m_EncryptionManager.AlignSize(BlockID, (Size + 3) & 0xfffffffc); // align on cipher after we aligned on 4 bytes + + TBlockHeadOcc h = {BlockID, Size + sizeof(TBlockHeadOcc) + sizeof(TBlockTailOcc), Signature}; + TBlockTailOcc t = {BlockID}; + + TBlockHeadOcc * block = (TBlockHeadOcc*) malloc(Size + sizeof(h) + sizeof(t)); + *block = h; + memset(block + 1, 0, Size); + *(TBlockTailOcc*)(((uint8_t*)(block + 1)) + Size) = t; + + TCacheEntry * ce = _CacheInsert(idx, block, false); + + if (m_ReadOnly) + { + TBlockTableEntry b = {false, true, 0}; + m_BlockTable[idx] = b; + } else { + uint32_t addr = _FindFreePosition(Size + sizeof(h) + sizeof(t)); + TBlockTableEntry b = {false, true, addr >> 2 }; + m_BlockTable[idx] = b; + + _UpdateBlock(BlockID, ce, addr); + } + + return ce->Cache + 1; +} + +void * CBlockManager::_CreateBlockVirtual(uint32_t & BlockID, const uint32_t Signature, uint32_t Size) +{ + uint32_t idx = _GetAvailableIndex(); + BlockID = idx << 2; + + Size = m_EncryptionManager.AlignSize(BlockID, (Size + 3) & 0xfffffffc); // align on cipher after we aligned on 4 bytes + + TBlockHeadOcc h = {BlockID, Size + sizeof(TBlockHeadOcc) + sizeof(TBlockTailOcc), Signature}; + TBlockTailOcc t = {BlockID}; + + TBlockHeadOcc * block = (TBlockHeadOcc*) malloc(Size + sizeof(h) + sizeof(t)); + *block = h; + memset(block + 1, 0, Size); + *(TBlockTailOcc*)(((uint8_t*)(block + 1)) + Size) = t; + + return _CacheInsert(idx, block, true)->Cache + 1; +} + +bool CBlockManager::DeleteBlock(uint32_t BlockID) +{ + uint32_t idx = BlockID >> 2; + uint32_t addr; + uint32_t size; + TCacheEntry * ce; + if (!_InitOperation(BlockID, addr, ce)) + return false; + + if (!ce->Forced) + XADD_32(m_CacheInfo.Size, 0 - ce->Cache->Size); + + if (ce->Pending) + _PendingRemove(ce->Pending, true); + + size = ce->Cache->Size; + _CacheErase(idx); + + if (addr == 0) // Block in memory only + { + TBlockTableEntry b = {false, false, 0}; + m_BlockTable[idx] = b; + + } else if (m_ReadOnly) + { + m_BlockTable[idx].Deleted = true; + m_BlockTable[idx].InCache = false; + } else { + _InsertFreeBlock(addr, size, true, true); + + TBlockTableEntry b = {false, false, 0}; + m_BlockTable[idx] = b; + } + + return true; +} + +uint32_t CBlockManager::_ResizeBlock(uint32_t BlockID, void * & Buffer, uint32_t Size) +{ + uint32_t idx = BlockID >> 2; + uint32_t addr; + TCacheEntry * ce; + + if (Size == 0) + return 0; + + if (!_InitOperation(BlockID, addr, ce)) + return 0; + + Size = m_EncryptionManager.AlignSize(BlockID, (Size + 3) & 0xfffffffc); // align on cipher after we aligned on 4 bytes + + uint32_t os = ce->Cache->Size; + uint32_t ns = Size + sizeof(TBlockHeadOcc) + sizeof(TBlockTailOcc); + if (ns == ce->Cache->Size) + { + Buffer = ce->Cache + 1; + return Size; + } + + ce->Cache = (TBlockHeadOcc*) realloc(ce->Cache, ns); + ce->Cache->Size = ns; + TBlockTailOcc t = {BlockID}; + *(TBlockTailOcc*)(((uint8_t*)(ce->Cache + 1)) + Size) = t; + XADD_32(m_CacheInfo.Size, ns - os); + + Buffer = ce->Cache + 1; + ce->KeepInCache = m_ReadOnly; + + if (!m_ReadOnly && addr) + { + _InsertFreeBlock(addr, os, true, true); + addr = _FindFreePosition(ns); + m_BlockTable[idx].Addr = addr >> 2; + + _UpdateBlock(BlockID, ce, addr); // write down + } + + return Size; +} + +bool CBlockManager::IsForcedVirtual(uint32_t BlockID) +{ + TCacheEntry * ce = _CacheFind(BlockID >> 2); + return ce && ce->Forced; +} + +bool CBlockManager::WriteBlockToDisk(uint32_t BlockID) +{ + uint32_t addr; + TCacheEntry * ce; + + if (!_InitOperation(BlockID, addr, ce)) + return false; + + if (!ce->Forced) + return true; + + ce->Forced = false; + XADD_32(m_CacheInfo.Size, ce->Cache->Size); + + if (!m_ReadOnly) + { + addr = _FindFreePosition(ce->Cache->Size); + m_BlockTable[BlockID >> 2].Addr = addr >> 2; + _UpdateBlock(BlockID, ce, addr); + } + return true; +} + +bool CBlockManager::MakeBlockVirtual(uint32_t BlockID) +{ + uint32_t addr; + TCacheEntry * ce; + + if (!_InitOperation(BlockID, addr, ce)) + return false; + + if (ce->Forced) + return true; + + if (ce->Pending) // don't write down, we kill it anyway + _PendingRemove(ce->Pending, true); + + ce->Forced = true; + XADD_32(m_CacheInfo.Size, 0 - ce->Cache->Size); + + if (!m_ReadOnly) + { + _InsertFreeBlock(addr, ce->Cache->Size, true, true); + m_BlockTable[BlockID >> 2].Addr = 0; + } + return true; +} + +void * CBlockManager::_ReadBlock(uint32_t BlockID, uint32_t & Size, uint32_t & Signature) +{ + uint32_t addr; + TCacheEntry * ce; + + if ((BlockID == 0) && (Signature == -1)) + { + Size = m_FirstBlockStart; + return m_Cache[0]->Cache; + } + + if (!_InitOperation(BlockID, addr, ce)) + return NULL; + + if ((Signature != 0) && (Signature != ce->Cache->Signature)) + { + Signature = ce->Cache->Signature; + return NULL; + } + Signature = ce->Cache->Signature; + + if ((Size != 0) && (Size != ce->Cache->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc))) + { + Size = ce->Cache->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc); + return NULL; + } + Size = ce->Cache->Size - sizeof(TBlockHeadOcc) - sizeof(TBlockTailOcc); + + return ce->Cache + 1; +} + +bool CBlockManager::UpdateBlock(uint32_t BlockID, uint32_t Signature) +{ + uint32_t addr; + TCacheEntry * ce; + + if ((BlockID == 0) && (Signature == -1)) + { + if (!m_ReadOnly) + _PendingAdd(0, 0, m_FirstBlockStart, m_Cache[0]); + + return true; + } + + if (!_InitOperation(BlockID, addr, ce)) + return false; + + if (Signature) + ce->Cache->Signature = Signature; + + _UpdateBlock(BlockID, ce, addr); + + return true; +} + +// make file writeable: +// write all cached blocks to file and check for the old addresses +// remove virtual only from file +// update m_FreeBlocks along the way + -- cgit v1.2.3