office-gobmx/store/source/storbios.cxx
Matteo Casalin 0871b509d2 Avoid explicit casts of (sizeof) constants known at compile time
Partially revert my previous commit eb4cbea657
"Silence some conversion warnings", since no warning was really raised for
these obvious conversions.

Change-Id: Ie035655cdc56ceeb12a6141b168f7e9a8b863fee
2015-08-29 16:57:05 +02:00

1104 lines
27 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "sal/config.h"
#include "storbios.hxx"
#include "sal/types.h"
#include "sal/macros.h"
#include "sal/log.hxx"
#include "rtl/alloc.h"
#include "rtl/ref.hxx"
#include "osl/diagnose.h"
#include "osl/mutex.hxx"
#include "store/types.h"
#include "object.hxx"
#include "lockbyte.hxx"
#include "storcach.hxx"
using namespace store;
/*========================================================================
*
* OStoreSuperBlock.
*
*======================================================================*/
#define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
struct OStoreSuperBlock
{
typedef OStorePageGuard G;
typedef OStorePageDescriptor D;
typedef OStorePageLink L;
/** Representation.
*/
G m_aGuard;
D m_aDescr;
sal_uInt32 m_nMarked;
L m_aMarked;
sal_uInt32 m_nUnused;
L m_aUnused;
/** theSize.
*/
static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
/** Construction.
*/
explicit OStoreSuperBlock (sal_uInt16 nPageSize)
: m_aGuard (STORE_MAGIC_SUPERBLOCK),
m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
m_nMarked (store::htonl(0)),
m_aMarked (0),
m_nUnused (store::htonl(0)),
m_aUnused (0)
{}
/** Comparison.
*/
bool operator== (const OStoreSuperBlock & rhs) const
{
return ((m_aGuard == rhs.m_aGuard ) &&
(m_aDescr == rhs.m_aDescr ) &&
(m_nMarked == rhs.m_nMarked) &&
(m_aMarked == rhs.m_aMarked) &&
(m_nUnused == rhs.m_nUnused) &&
(m_aUnused == rhs.m_aUnused) );
}
/** unused(Count|Head|Insert|Remove|Reset).
*/
sal_uInt32 unusedCount() const
{
return store::ntohl(m_nUnused);
}
const L& unusedHead() const
{
return m_aUnused;
}
void unusedInsert (const L& rLink)
{
sal_uInt32 nUnused = unusedCount();
m_nUnused = store::htonl(nUnused + 1);
m_aUnused = rLink;
}
void unusedRemove (const L& rLink)
{
sal_uInt32 nUnused = unusedCount();
m_nUnused = store::htonl(nUnused - 1);
m_aUnused = rLink;
}
void unusedReset()
{
m_nUnused = store::htonl(0);
m_aUnused = L(0);
}
/** guard (external representation).
*/
void guard()
{
sal_uInt32 nCRC32 = 0;
nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, static_cast<sal_uInt32>(theSize - sizeof(G)));
m_aGuard.m_nCRC32 = store::htonl(nCRC32);
}
/** verify (external representation).
*/
storeError verify() const
{
sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
if (nMagic != STORE_MAGIC_SUPERBLOCK)
return store_E_WrongFormat;
sal_uInt32 nCRC32 = 0;
nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, static_cast<sal_uInt32>(theSize - sizeof(G)));
if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
return store_E_InvalidChecksum;
else
return store_E_None;
}
};
/*========================================================================
*
* SuperBlockPage interface.
*
*======================================================================*/
namespace store
{
struct SuperBlockPage
{
typedef OStoreSuperBlock SuperBlock;
/** Representation.
*/
SuperBlock m_aSuperOne;
SuperBlock m_aSuperTwo;
/** theSize.
*/
static const size_t theSize = 2 * SuperBlock::theSize;
static const sal_uInt16 thePageSize = theSize;
static_assert(STORE_MINIMUM_PAGESIZE >= thePageSize, "must be at least thePageSize");
/** Allocation.
*/
static void * operator new (size_t n)
{
return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
}
static void operator delete (void * p)
{
rtl_freeMemory (p);
}
static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize)
{
return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
}
static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16)
{
rtl_freeMemory (p);
}
/** Construction.
*/
explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
: m_aSuperOne(nPageSize),
m_aSuperTwo(nPageSize)
{}
/** save.
*/
storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
{
m_aSuperOne.guard();
m_aSuperTwo = m_aSuperOne;
return rBIOS.write (0, this, nSize);
}
/** Page allocation.
*/
storeError unusedHead (
OStorePageBIOS & rBIOS,
PageData & rPageHead);
storeError unusedPop (
OStorePageBIOS & rBIOS,
PageData const & rPageHead);
storeError unusedPush (
OStorePageBIOS & rBIOS,
sal_uInt32 nAddr);
/** verify (with repair).
*/
storeError verify (OStorePageBIOS & rBIOS);
};
} // namespace store
/*========================================================================
*
* SuperBlockPage implementation.
*
*======================================================================*/
/*
* unusedHead(): get freelist head (alloc page, step 1).
*/
storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
{
storeError eErrCode = verify (rBIOS);
if (eErrCode != store_E_None)
return eErrCode;
// Check freelist head.
OStorePageLink const aListHead (m_aSuperOne.unusedHead());
if (aListHead.location() == 0)
{
// Freelist empty, see SuperBlock::ctor().
rPageHead.location (STORE_PAGE_NULL);
return store_E_None;
}
// Load PageHead.
eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
if (eErrCode != store_E_None)
return eErrCode;
eErrCode = rPageHead.verify (aListHead.location());
if (eErrCode != store_E_None)
return eErrCode;
// Verify page is unused.
sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
if (nAddr == STORE_PAGE_NULL)
{
SAL_WARN("store", "store::SuperBlock::unusedHead(): page not free");
// Page in use.
rPageHead.location (STORE_PAGE_NULL);
// Recovery: Reset freelist to empty.
m_aSuperOne.unusedReset();
eErrCode = save (rBIOS);
}
return eErrCode;
}
/*
* unusedPop(): pop freelist head (alloc page, step 2).
*/
storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
{
sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
if (nAddr == STORE_PAGE_NULL)
return store_E_CantSeek;
// Pop from FreeList.
OStorePageLink const aListHead (nAddr);
m_aSuperOne.unusedRemove (aListHead);
return save (rBIOS);
}
/*
* unusedPush(): push new freelist head.
*/
storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
{
storeError eErrCode = verify (rBIOS);
if (eErrCode != store_E_None)
return eErrCode;
PageData aPageHead;
eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
if (eErrCode != store_E_None)
return eErrCode;
eErrCode = aPageHead.verify (nAddr);
if (eErrCode != store_E_None)
return eErrCode;
aPageHead.m_aUnused = m_aSuperOne.unusedHead();
aPageHead.guard (nAddr);
eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
if (eErrCode != store_E_None)
return eErrCode;
OStorePageLink const aListHead (nAddr);
m_aSuperOne.unusedInsert(aListHead);
return save (rBIOS);
}
/*
* verify (with repair).
*/
storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
{
// Verify 1st copy.
storeError eErrCode = m_aSuperOne.verify();
if (eErrCode == store_E_None)
{
// Ok. Verify 2nd copy.
eErrCode = m_aSuperTwo.verify();
if (eErrCode == store_E_None)
{
// Ok. Ensure identical copies (1st copy wins).
if (!(m_aSuperOne == m_aSuperTwo))
{
// Different. Replace 2nd copy with 1st copy.
m_aSuperTwo = m_aSuperOne;
// Write back.
if (rBIOS.isWriteable())
eErrCode = rBIOS.write (0, this, theSize);
else
eErrCode = store_E_None;
}
}
else
{
// Failure. Replace 2nd copy with 1st copy.
m_aSuperTwo = m_aSuperOne;
// Write back.
if (rBIOS.isWriteable())
eErrCode = rBIOS.write (0, this, theSize);
else
eErrCode = store_E_None;
}
}
else
{
// Failure. Verify 2nd copy.
eErrCode = m_aSuperTwo.verify();
if (eErrCode == store_E_None)
{
// Ok. Replace 1st copy with 2nd copy.
m_aSuperOne = m_aSuperTwo;
// Write back.
if (rBIOS.isWriteable())
eErrCode = rBIOS.write (0, this, theSize);
else
eErrCode = store_E_None;
}
else
{
// Double Failure.
OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
}
}
// Done.
return eErrCode;
}
/*========================================================================
*
* OStorePageBIOS::Ace implementation.
*
*======================================================================*/
OStorePageBIOS::Ace::Ace()
: m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
{}
OStorePageBIOS::Ace::~Ace()
{
m_next->m_prev = m_prev, m_prev->m_next = m_next;
}
int
SAL_CALL OStorePageBIOS::Ace::constructor (
void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
{
Ace * ace = static_cast<Ace*>(obj);
ace->m_next = ace->m_prev = ace;
return 1;
}
OStorePageBIOS::Ace *
OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
{
OStorePageBIOS::Ace * entry;
for (entry = head->m_next; entry != head; entry = entry->m_next)
{
if (entry->m_addr >= addr)
return entry;
}
return head;
}
void
OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
{
// insert entry at queue tail (before head).
entry->m_next = head;
entry->m_prev = head->m_prev;
head->m_prev = entry;
entry->m_prev->m_next = entry;
}
/*========================================================================
*
* OStorePageBIOS::AceCache interface.
*
*======================================================================*/
namespace store
{
class OStorePageBIOS::AceCache
{
rtl_cache_type * m_ace_cache;
public:
static AceCache & get();
OStorePageBIOS::Ace *
create (sal_uInt32 addr, sal_uInt32 used = 1);
void
destroy (OStorePageBIOS::Ace * ace);
protected:
AceCache();
~AceCache();
};
} // namespace store
/*========================================================================
*
* OStorePageBIOS::AceCache implementation.
*
*======================================================================*/
extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
OStorePageBIOS::AceCache &
OStorePageBIOS::AceCache::get()
{
static AceCache g_ace_cache;
return g_ace_cache;
}
OStorePageBIOS::AceCache::AceCache()
{
m_ace_cache = rtl_cache_create (
"store_ace_cache",
sizeof (OStorePageBIOS::Ace),
0, // objalign
reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
0, // destructor,
0, // reclaim,
0, // userarg,
0, // default source,
0 // flags
);
}
OStorePageBIOS::AceCache::~AceCache()
{
rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
}
OStorePageBIOS::Ace *
OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
{
Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
if (ace != 0)
{
// verify invariant state.
OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
// initialize.
ace->m_addr = addr;
ace->m_used = used;
}
return ace;
}
void
OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
{
if (ace != 0)
{
// remove from queue (if any).
ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
// restore invariant state.
ace->m_next = ace->m_prev = ace;
// return to cache.
rtl_cache_free (m_ace_cache, ace);
}
}
/*========================================================================
*
* OStorePageBIOS implementation.
*
*======================================================================*/
/*
* OStorePageBIOS.
*/
OStorePageBIOS::OStorePageBIOS()
: m_xLockBytes (NULL),
m_pSuper (NULL),
m_bWriteable (false)
{
}
/*
* ~OStorePageBIOS.
*/
OStorePageBIOS::~OStorePageBIOS()
{
cleanup_Impl();
}
/*
* initialize.
* Precond: none.
*/
storeError OStorePageBIOS::initialize (
ILockBytes * pLockBytes,
storeAccessMode eAccessMode,
sal_uInt16 & rnPageSize)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Initialize.
storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
if (eErrCode != store_E_None)
{
// Cleanup.
cleanup_Impl();
}
return eErrCode;
}
/*
* initialize_Impl.
* Internal: Precond: exclusive access.
*/
storeError OStorePageBIOS::initialize_Impl (
ILockBytes * pLockBytes,
storeAccessMode eAccessMode,
sal_uInt16 & rnPageSize)
{
// Cleanup.
cleanup_Impl();
// Initialize.
m_xLockBytes = pLockBytes;
if (!m_xLockBytes.is())
return store_E_InvalidParameter;
m_bWriteable = (eAccessMode != store_AccessReadOnly);
// Check access mode.
storeError eErrCode = store_E_None;
if (eAccessMode != store_AccessCreate)
{
// Load SuperBlock page.
if ((m_pSuper = new SuperBlockPage()) == 0)
return store_E_OutOfMemory;
eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
if (eErrCode == store_E_None)
{
// Verify SuperBlock page (with repair).
eErrCode = m_pSuper->verify (*this);
}
}
else
{
// Truncate to zero length.
eErrCode = m_xLockBytes->setSize(0);
if (eErrCode != store_E_None)
return eErrCode;
// Mark as not existing.
eErrCode = store_E_NotExists;
}
if (eErrCode != store_E_None)
{
// Check reason.
if (eErrCode != store_E_NotExists)
return eErrCode;
// Check mode.
if (eAccessMode == store_AccessReadOnly)
return store_E_NotExists;
if (eAccessMode == store_AccessReadWrite)
return store_E_NotExists;
// Check PageSize.
if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
return store_E_InvalidParameter;
rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
// Create initial page (w/ SuperBlock).
if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
return store_E_OutOfMemory;
eErrCode = m_pSuper->save (*this, rnPageSize);
}
if (eErrCode == store_E_None)
{
// Obtain page size.
rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
// Create page allocator.
eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
if (eErrCode != store_E_None)
return eErrCode;
// Create page cache.
eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
}
return eErrCode;
}
/*
* cleanup_Impl.
* Internal: Precond: exclusive access.
*/
void OStorePageBIOS::cleanup_Impl()
{
// Check referer count.
if (m_ace_head.m_used > 0)
{
// Report remaining referer count.
SAL_INFO("store", "referer count: " << m_ace_head.m_used);
for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
{
m_ace_head.m_used -= ace->m_used;
AceCache::get().destroy (ace);
}
OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
}
// Release SuperBlock page.
delete m_pSuper, m_pSuper = 0;
// Release PageCache.
m_xCache.clear();
// Release PageAllocator.
m_xAllocator.clear();
// Release LockBytes.
m_xLockBytes.clear();
}
/*
* read.
* Low Level: Precond: initialized, exclusive access.
*/
storeError OStorePageBIOS::read (
sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
{
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Read Data.
return m_xLockBytes->readAt (nAddr, pData, nSize);
}
/*
* write.
* Low Level: Precond: initialized, writeable, exclusive access.
*/
storeError OStorePageBIOS::write (
sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
{
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
if (!m_bWriteable)
return store_E_AccessViolation;
// Write Data.
return m_xLockBytes->writeAt (nAddr, pData, nSize);
}
/*
* acquirePage.
* Precond: initialized.
*/
storeError OStorePageBIOS::acquirePage (
const OStorePageDescriptor& rDescr, storeAccessMode eMode)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Check access mode.
if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
return store_E_AccessViolation;
// Find access control list entry.
Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
if (ace->m_addr == rDescr.m_nAddr)
{
// Acquire existing entry (with ShareDenyWrite).
if (eMode == store_AccessReadOnly)
ace->m_used += 1;
else
return store_E_AccessViolation;
}
else
{
// Insert new entry.
Ace * entry = AceCache::get().create (rDescr.m_nAddr);
if (!entry)
return store_E_OutOfMemory;
Ace::insert (ace, entry);
}
// Increment total referer count and finish.
m_ace_head.m_used += 1;
return store_E_None;
}
/*
* releasePage.
* Precond: initialized.
*/
storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Find access control list entry.
Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
if (ace->m_addr != rDescr.m_nAddr)
return store_E_NotExists;
// Release existing entry.
if (ace->m_used > 1)
ace->m_used -= 1;
else
AceCache::get().destroy (ace);
// Decrement total referer count and finish.
m_ace_head.m_used -= 1;
return store_E_None;
}
/*
* getRefererCount.
* Precond: none.
*/
sal_uInt32 OStorePageBIOS::getRefererCount()
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Obtain total referer count.
return m_ace_head.m_used;
}
/*
* allocate.
* Precond: initialized, writeable.
*/
storeError OStorePageBIOS::allocate (
OStorePageObject& rPage, Allocation eAlloc)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
if (!m_bWriteable)
return store_E_AccessViolation;
// Check allocation type.
storeError eErrCode = store_E_None;
if (eAlloc != ALLOCATE_EOF)
{
// Try freelist head.
PageData aPageHead;
eErrCode = m_pSuper->unusedHead (*this, aPageHead);
if (eErrCode != store_E_None)
return eErrCode;
sal_uInt32 const nAddr = aPageHead.location();
if (nAddr != STORE_PAGE_NULL)
{
// Save page.
eErrCode = saveObjectAt_Impl (rPage, nAddr);
if (eErrCode != store_E_None)
return eErrCode;
// Pop freelist head and finish.
return m_pSuper->unusedPop (*this, aPageHead);
}
}
// Allocate from EOF. Determine current size.
sal_uInt32 nSize = STORE_PAGE_NULL;
eErrCode = m_xLockBytes->getSize (nSize);
if (eErrCode != store_E_None)
return eErrCode;
// Save page at current EOF.
return saveObjectAt_Impl (rPage, nSize);
}
/*
* free.
* Precond: initialized, writeable.
*/
storeError OStorePageBIOS::free (sal_uInt32 nAddr)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
if (!m_bWriteable)
return store_E_AccessViolation;
// Invalidate cache.
(void) m_xCache->removePageAt (nAddr);
// Push onto freelist.
return m_pSuper->unusedPush (*this, nAddr);
}
/*
* loadObjectAt.
* Precond: initialized, readable.
*/
storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
return loadObjectAt_Impl (rPage, nAddr);
}
/*
* loadObjectAt_Impl.
* Internal: Precond: initialized, readable, exclusive access.
*/
storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
{
storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
if (eErrCode != store_E_NotExists)
return eErrCode;
// Read page.
eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
if (eErrCode != store_E_None)
return eErrCode;
// Verify page.
eErrCode = rPage.verify (nAddr);
if (eErrCode != store_E_None)
return eErrCode;
// Mark page as clean.
rPage.clean();
// Cache page.
return m_xCache->insertPageAt (rPage.get(), nAddr);
}
/*
* saveObjectAt.
* Precond: initialized, writeable.
*/
storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
if (!m_bWriteable)
return store_E_AccessViolation;
// Save Page.
return saveObjectAt_Impl (rPage, nAddr);
}
/*
* saveObjectAt_Impl.
* Internal: Precond: initialized, writeable, exclusive access.
*/
storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
{
// Guard page (incl. set location).
storeError eErrCode = rPage.guard (nAddr);
if (eErrCode != store_E_None)
return eErrCode;
// Write page.
eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
if (eErrCode != store_E_None)
return eErrCode;
// Mark page as clean.
rPage.clean();
// Cache page.
return m_xCache->updatePageAt (rPage.get(), nAddr);
}
/*
* close.
* Precond: none.
*/
storeError OStorePageBIOS::close()
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Cleanup.
cleanup_Impl();
// Done.
return store_E_None;
}
/*
* flush.
* Precond: initialized.
*/
storeError OStorePageBIOS::flush()
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Flush LockBytes and finish.
return m_xLockBytes->flush();
}
/*
* size.
* Precond: initialized.
*/
storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Initialize [out] param.
rnSize = 0;
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Obtain LockBytes size.
return m_xLockBytes->getSize (rnSize);
}
/*
* scanBegin.
* Precond: initialized.
*/
storeError OStorePageBIOS::scanBegin (
ScanContext &rCtx, sal_uInt32 nMagic)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Initialize [out] param.
rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
rCtx.m_nSize = 0;
rCtx.m_nMagic = nMagic;
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Check SuperBlock page.
storeError eErrCode = m_pSuper->verify (*this);
if (eErrCode != store_E_None)
{
// Damaged. Determine page size (NYI).
OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
return eErrCode;
}
// Setup Context descriptor.
rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
// Setup Context size.
eErrCode = size (rCtx.m_nSize);
if (eErrCode != store_E_None)
rCtx.m_nSize = ((sal_uInt32)(~0));
// Done.
return store_E_None;
}
/*
* scanNext.
* Precond: initialized.
*/
storeError OStorePageBIOS::scanNext (
ScanContext &rCtx, OStorePageObject &rPage)
{
// Acquire exclusive access.
osl::MutexGuard aGuard (m_aMutex);
// Check precond.
if (!m_xLockBytes.is())
return store_E_InvalidAccess;
// Setup PageHead.
PageData aPageHead;
// Check context.
while (rCtx.isValid())
{
// Assign next location.
sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
// Read PageHead.
storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
if (eErrCode != store_E_None)
continue;
// Verify PageHead.
eErrCode = aPageHead.verify (nAddr);
if (eErrCode != store_E_None)
continue;
// Check PageHead Magic number.
if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
continue;
// Check PageHead Unused link.
if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
continue;
// Load page.
eErrCode = loadObjectAt_Impl (rPage, nAddr);
if (eErrCode != store_E_None)
continue;
// Deliver page.
return store_E_None;
}
// Done.
return store_E_CantSeek;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */