summaryrefslogtreecommitdiff
path: root/store/source/storbios.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'store/source/storbios.cxx')
-rw-r--r--store/source/storbios.cxx1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/store/source/storbios.cxx b/store/source/storbios.cxx
new file mode 100644
index 000000000000..d2612d60b3db
--- /dev/null
+++ b/store/source/storbios.cxx
@@ -0,0 +1,1129 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_store.hxx"
+
+#include "storbios.hxx"
+
+#include "sal/types.h"
+#include "sal/macros.h"
+
+#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)
+ {}
+
+ OStoreSuperBlock (const OStoreSuperBlock & rhs)
+ : 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)
+ {}
+
+ OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs)
+ {
+ 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;
+ return *this;
+ }
+
+ /** Comparison.
+ */
+ sal_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 (void) const
+ {
+ return store::ntohl(m_nUnused);
+ }
+ const L& unusedHead (void) 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 (void)
+ {
+ 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, 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, 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;
+ STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize);
+
+ /** Allocation.
+ */
+ static void * operator new (size_t n) SAL_THROW(())
+ {
+ return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
+ }
+ static void operator delete (void * p, size_t) SAL_THROW(())
+ {
+ rtl_freeMemory (p);
+ }
+
+ static void * operator new (size_t, sal_uInt16 nPageSize) SAL_THROW(())
+ {
+ return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
+ }
+ static void operator delete (void * p, sal_uInt16) SAL_THROW(())
+ {
+ 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();
+ OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free");
+ if (nAddr == STORE_PAGE_NULL)
+ {
+ // 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.\n");
+ }
+ }
+
+ // 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, 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 (void)
+ : m_xLockBytes (NULL),
+ m_pSuper (NULL),
+ m_bWriteable (false)
+{
+}
+
+/*
+ * ~OStorePageBIOS.
+ */
+OStorePageBIOS::~OStorePageBIOS (void)
+{
+ 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.
+ OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d\n", 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, 1);
+ 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, storeAccessMode /* eMode */)
+{
+ // 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 (void)
+{
+ // 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 (void)
+{
+ // 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;
+}