office-gobmx/store/source/storpage.cxx
2010-03-04 19:36:24 +01:00

1057 lines
29 KiB
C++

/*************************************************************************
*
* 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 "storpage.hxx"
#include "sal/types.h"
#include "rtl/string.h"
#include "rtl/ref.hxx"
#include "osl/diagnose.h"
#include "osl/mutex.hxx"
#include "store/types.h"
#include "object.hxx"
#include "lockbyte.hxx"
#include "storbase.hxx"
#include "stordata.hxx"
#include "stortree.hxx"
using namespace store;
/*========================================================================
*
* OStorePageManager implementation.
*
*======================================================================*/
const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
/*
* OStorePageManager.
*/
OStorePageManager::OStorePageManager (void)
{
}
/*
* ~OStorePageManager.
*/
OStorePageManager::~OStorePageManager (void)
{
}
/*
* isKindOf.
*/
sal_Bool SAL_CALL OStorePageManager::isKindOf (sal_uInt32 nTypeId)
{
return (nTypeId == m_nTypeId);
}
/*
* initialize (two-phase construction).
* Precond: none.
*/
storeError OStorePageManager::initialize (
ILockBytes * pLockBytes,
storeAccessMode eAccessMode,
sal_uInt16 & rnPageSize)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check arguments.
if (!pLockBytes)
return store_E_InvalidParameter;
// Initialize base.
storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
if (eErrCode != store_E_None)
return eErrCode;
// Check for (not) writeable.
if (!base::isWriteable())
{
// Readonly. Load RootNode.
return base::loadObjectAt (m_aRoot, rnPageSize);
}
// Writeable. Load or Create RootNode.
eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
if (eErrCode == store_E_Pending)
{
// Creation notification.
PageHolderObject< page > xRoot (m_aRoot.get());
// Pre-allocate left most entry (ugly, but we can't insert to left).
OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
xRoot->insert (0, entry(aKey));
// Save RootNode.
eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
}
// Done.
return eErrCode;
}
/*
* find_lookup (w/o split()).
* Internal: Precond: initialized, readable, exclusive access.
*/
storeError OStorePageManager::find_lookup (
OStoreBTreeNodeObject & rNode,
sal_uInt16 & rIndex,
OStorePageKey const & rKey)
{
// Find Node and Index.
storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
if (eErrCode != store_E_None)
return eErrCode;
// Greater or Equal.
PageHolderObject< page > xPage (rNode.get());
OSL_POSTCOND(rIndex < xPage->usageCount(), "store::PageManager::find_lookup(): logic error");
entry e (xPage->m_pData[rIndex]);
// Check for exact match.
if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
{
// Page not present.
return store_E_NotExists;
}
// Check address.
if (e.m_aLink.location() == STORE_PAGE_NULL)
{
// Page not present.
return store_E_NotExists;
}
return store_E_None;
}
/*
* remove_Impl (possibly down from root).
* Internal: Precond: initialized, writeable, exclusive access.
*/
#if 0 /* EXP */
storeError OStorePageManager::remove_Impl (entry & rEntry)
{
// Find Node and Index.
OStoreBTreeNodeObject aNode;
sal_uInt16 nIndex = 0;
eErrCode = m_aRoot.find_lookup (aNode, nIndex, entry::CompareGreater(rEntry), *this);
// @@@
PageHolderObject< page > xPage (aNode.get());
page & rPage = (*xPage);
// Check current page index.
sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount();
if (!(i < n))
{
// Path to entry not exists (Must not happen(?)).
return store_E_NotExists;
}
// Compare entry.
entry::CompareResult result = rEntry.compare (rPage.m_pData[i]);
for (; result == entry::COMPARE_GREATER && xPage->depth() > 0; )
{
// Check next node address.
sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
if (nAddr == STORE_PAGE_NULL)
{
// Path to entry not exists (Must not happen(?)).
return store_E_NotExists;
}
// Load next node page.
eErrCode = loadObjectAt (aNode, nAddr);
PageHolderObject< page > xNext (aNode.get());
xNext.swap (xPage);
}
aNode.remove (nIndex, rEntry, *this);
do
{
// Load next node page.
eErrCode = loadObjectAt (aNode, nAddr);
page const & rPage = (*xPage);
// Check current page index.
sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount();
if (!(i < n))
{
// Path to entry not exists (Must not happen(?)).
return store_E_NotExists;
}
// Compare entry.
result = rEntry.compare (rPage.m_pData[i]);
} while (result == entry::COMPATE_GREATER);
}
#endif /* EXP */
storeError OStorePageManager::remove_Impl (entry & rEntry)
{
OStoreBTreeNodeObject aNode (m_aRoot.get());
// Check current page index.
PageHolderObject< page > xPage (aNode.get());
sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
if (!(i < n))
{
// Path to entry not exists (Must not happen(?)).
return store_E_NotExists;
}
// Compare entry.
entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
// Iterate down until equal match.
while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
{
// Check link address.
sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
if (nAddr == STORE_PAGE_NULL)
{
// Path to entry not exists (Must not happen(?)).
return store_E_NotExists;
}
// Load link page.
storeError eErrCode = loadObjectAt (aNode, nAddr);
if (eErrCode != store_E_None)
return eErrCode;
PageHolderObject< page > xNext (aNode.get());
xNext.swap (xPage);
// Check index.
i = xPage->find (rEntry), n = xPage->usageCount();
if (!(i < n))
{
// Path to entry not exists (Must not happen(?)).
return store_E_NotExists;
}
// Compare entry.
result = rEntry.compare (xPage->m_pData[i]);
}
OSL_POSTCOND(
result != entry::COMPARE_LESS,
"OStorePageManager::remove(): find failed");
// Check entry comparison.
if (result == entry::COMPARE_LESS)
{
// Must not happen.
return store_E_Unknown;
}
// Remove down from current page (recursive).
return aNode.remove (i, rEntry, *this);
}
/*
* namei.
* Precond: none (static).
*/
storeError OStorePageManager::namei (
const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
{
// Check parameter.
if (!(pPath && pName))
return store_E_InvalidParameter;
// Check name length.
if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
return store_E_NameTooLong;
// Transform pathname into key.
rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
// Done.
return store_E_None;
}
/*
* iget.
* Precond: initialized.
*/
storeError OStorePageManager::iget (
OStoreDirectoryPageObject & rPage,
sal_uInt32 nAttrib,
const rtl_String * pPath,
const rtl_String * pName,
storeAccessMode eMode)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
// Setup inode page key.
OStorePageKey aKey;
storeError eErrCode = namei (pPath, pName, aKey);
if (eErrCode != store_E_None)
return eErrCode;
// Check for directory.
if (nAttrib & STORE_ATTRIB_ISDIR)
{
// Ugly, but necessary (backward compatibility).
aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
}
// Load inode page.
eErrCode = load_dirpage_Impl (aKey, rPage);
if (eErrCode != store_E_None)
{
// Check mode and reason.
if (eErrCode != store_E_NotExists)
return eErrCode;
if (eMode == store_AccessReadWrite)
return store_E_NotExists;
if (eMode == store_AccessReadOnly)
return store_E_NotExists;
if (!base::isWriteable())
return store_E_AccessViolation;
// Create inode page.
eErrCode = rPage.construct< inode >(base::allocator());
if (eErrCode != store_E_None)
return eErrCode;
// Setup inode nameblock.
PageHolderObject< inode > xPage (rPage.get());
rPage.key (aKey);
rPage.attrib (nAttrib);
memcpy (
&(xPage->m_aNameBlock.m_pData[0]),
pName->buffer, pName->length);
// Save inode page.
eErrCode = save_dirpage_Impl (aKey, rPage);
if (eErrCode != store_E_None)
return eErrCode;
}
// Check for symbolic link.
if (rPage.attrib() & STORE_ATTRIB_ISLINK)
{
// Obtain 'Destination' page key.
PageHolderObject< inode > xPage (rPage.get());
OStorePageKey aDstKey;
memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
// Load 'Destination' inode.
eErrCode = load_dirpage_Impl (aDstKey, rPage);
if (eErrCode != store_E_None)
return eErrCode;
}
// Done.
return store_E_None;
}
/*
* iterate.
* Precond: initialized.
* ToDo: skip hardlink entries.
*/
storeError OStorePageManager::iterate (
OStorePageKey & rKey,
OStorePageLink & rLink,
sal_uInt32 & rAttrib)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
// Find NodePage and Index.
OStoreBTreeNodeObject aNode;
sal_uInt16 i = 0;
storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
if (eErrCode != store_E_None)
return eErrCode;
// GreaterEqual. Found next entry.
PageHolderObject< page > xNode (aNode.get());
entry e (xNode->m_pData[i]);
// Setup result.
rKey = e.m_aKey;
rLink = e.m_aLink;
rAttrib = store::ntohl(e.m_nAttrib);
// Done.
return store_E_None;
}
/*
* load => private: iget() @@@
* Internal: Precond: initialized, exclusive access.
*/
storeError OStorePageManager::load_dirpage_Impl (
const OStorePageKey &rKey,
OStoreDirectoryPageObject &rPage)
{
// Find Node and Index.
OStoreBTreeNodeObject aNode;
sal_uInt16 i = 0;
storeError eErrCode = find_lookup (aNode, i, rKey);
if (eErrCode != store_E_None)
return eErrCode;
// Existing entry. Load page.
PageHolderObject< page > xNode (aNode.get());
entry e (xNode->m_pData[i]);
return loadObjectAt (rPage, e.m_aLink.location());
}
/*
* save => private: iget(), rebuild() @@@
* Internal: Precond: initialized, writeable, exclusive access.
*/
storeError OStorePageManager::save_dirpage_Impl (
const OStorePageKey &rKey,
OStoreDirectoryPageObject &rPage)
{
// Find NodePage and Index.
node aNode;
sal_uInt16 i = 0;
storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
PageHolderObject< page > xNode (aNode.get());
if (eErrCode != store_E_None)
{
if (eErrCode != store_E_AlreadyExists)
return eErrCode;
// Existing entry.
entry e (xNode->m_pData[i]);
if (e.m_aLink.location() != STORE_PAGE_NULL)
{
// Save page to existing location.
return saveObjectAt (rPage, e.m_aLink.location());
}
// Allocate page.
eErrCode = base::allocate (rPage);
if (eErrCode != store_E_None)
return eErrCode;
// Update page location.
xNode->m_pData[i].m_aLink = rPage.location();
// Save modified NodePage.
return saveObjectAt (aNode, aNode.location());
}
// Allocate page.
eErrCode = base::allocate (rPage);
if (eErrCode != store_E_None)
return eErrCode;
// Insert.
OStorePageLink aLink (rPage.location());
xNode->insert (i + 1, entry (rKey, aLink));
// Save modified NodePage.
return saveObjectAt (aNode, aNode.location());
}
/*
* attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)].
* Precond: initialized.
*/
storeError OStorePageManager::attrib (
const OStorePageKey &rKey,
sal_uInt32 nMask1,
sal_uInt32 nMask2,
sal_uInt32 &rAttrib)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
// Find NodePage and index.
OStoreBTreeNodeObject aNode;
sal_uInt16 i = 0;
storeError eErrCode = find_lookup (aNode, i, rKey);
if (eErrCode != store_E_None)
return eErrCode;
// Existing entry.
PageHolderObject< page > xNode (aNode.get());
entry e (xNode->m_pData[i]);
if (nMask1 != nMask2)
{
// Evaluate new attributes.
sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib);
nAttrib &= ~nMask1;
nAttrib |= nMask2;
if (store::htonl(nAttrib) != e.m_nAttrib)
{
// Check access mode.
if (base::isWriteable())
{
// Set new attributes.
e.m_nAttrib = store::htonl(nAttrib);
xNode->m_pData[i] = e;
// Save modified NodePage.
eErrCode = saveObjectAt (aNode, aNode.location());
}
else
{
// Access denied.
eErrCode = store_E_AccessViolation;
}
}
}
// Obtain current attributes.
rAttrib = store::ntohl(e.m_nAttrib);
return eErrCode;
}
/*
* link (insert 'Source' as hardlink to 'Destination').
* Precond: initialized, writeable.
*/
storeError OStorePageManager::link (
const OStorePageKey &rSrcKey,
const OStorePageKey &rDstKey)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
if (!base::isWriteable())
return store_E_AccessViolation;
// Find 'Destination' NodePage and Index.
OStoreBTreeNodeObject aDstNode;
sal_uInt16 i = 0;
storeError eErrCode = find_lookup (aDstNode, i, rDstKey);
if (eErrCode != store_E_None)
return eErrCode;
// Existing 'Destination' entry.
PageHolderObject< page > xDstNode (aDstNode.get());
entry e (xDstNode->m_pData[i]);
OStorePageLink aDstLink (e.m_aLink);
// Find 'Source' NodePage and Index.
OStoreBTreeNodeObject aSrcNode;
eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this);
if (eErrCode != store_E_None)
return eErrCode;
// Insert 'Source' entry.
PageHolderObject< page > xSrcNode (aSrcNode.get());
xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK));
return saveObjectAt (aSrcNode, aSrcNode.location());
}
/*
* symlink (insert 'Source' DirectoryPage as symlink to 'Destination').
* Precond: initialized, writeable.
*/
storeError OStorePageManager::symlink (
const rtl_String *pSrcPath,
const rtl_String *pSrcName,
const OStorePageKey &rDstKey)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
if (!base::isWriteable())
return store_E_AccessViolation;
// Check 'Source' parameter.
storeError eErrCode = store_E_InvalidParameter;
if (!(pSrcPath && pSrcName))
return eErrCode;
// Setup 'Source' page key.
OStorePageKey aSrcKey;
eErrCode = namei (pSrcPath, pSrcName, aSrcKey);
if (eErrCode != store_E_None)
return eErrCode;
// Find 'Source' NodePage and Index.
OStoreBTreeNodeObject aSrcNode;
sal_uInt16 i = 0;
eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this);
if (eErrCode != store_E_None)
return eErrCode;
// Initialize directory page.
OStoreDirectoryPageObject aPage;
eErrCode = aPage.construct< inode >(base::allocator());
if (eErrCode != store_E_None)
return eErrCode;
// Setup as 'Source' directory page.
inode_holder_type xNode (aPage.get());
aPage.key (aSrcKey);
memcpy (
&(xNode->m_aNameBlock.m_pData[0]),
pSrcName->buffer, pSrcName->length);
// Store 'Destination' page key.
OStorePageKey aDstKey (rDstKey);
memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey));
// Mark 'Source' as symbolic link to 'Destination'.
aPage.attrib (STORE_ATTRIB_ISLINK);
aPage.dataLength (sal_uInt32(sizeof(aDstKey)));
// Allocate and save 'Source' directory page.
eErrCode = base::allocate (aPage);
if (eErrCode != store_E_None)
return eErrCode;
// Insert 'Source' entry.
PageHolderObject< page > xSrcNode (aSrcNode.get());
OStorePageLink aSrcLink (aPage.location());
xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink));
// Save modified NodePage.
return saveObjectAt (aSrcNode, aSrcNode.location());
}
/*
* rename.
* Precond: initialized, writeable.
*/
storeError OStorePageManager::rename (
const OStorePageKey &rSrcKey,
const rtl_String *pDstPath,
const rtl_String *pDstName)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
if (!base::isWriteable())
return store_E_AccessViolation;
// Check 'Destination' parameter.
storeError eErrCode = store_E_InvalidParameter;
if (!(pDstPath && pDstName))
return eErrCode;
// Setup 'Destination' page key.
OStorePageKey aDstKey;
eErrCode = namei (pDstPath, pDstName, aDstKey);
if (eErrCode != store_E_None)
return eErrCode;
// Find 'Source' NodePage and Index.
OStoreBTreeNodeObject aSrcNode;
sal_uInt16 i = 0;
eErrCode = find_lookup (aSrcNode, i, rSrcKey);
if (eErrCode != store_E_None)
return eErrCode;
// Existing 'Source' entry.
PageHolderObject< page > xSrcNode (aSrcNode.get());
entry e (xSrcNode->m_pData[i]);
// Check for (not a) hardlink.
OStoreDirectoryPageObject aPage;
if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
{
// Load directory page.
eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
if (eErrCode != store_E_None)
return eErrCode;
// Check for directory.
if (aPage.attrib() & STORE_ATTRIB_ISDIR)
{
// Ugly, but necessary (backward compatibility).
aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1));
}
}
// Let 'Source' entry be 'Destination' entry.
e.m_aKey = aDstKey;
// Find 'Destination' NodePage and Index.
OStoreBTreeNodeObject aDstNode;
eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this);
if (eErrCode != store_E_None)
return eErrCode;
// Insert 'Destination' entry.
PageHolderObject< page > xDstNode (aDstNode.get());
xDstNode->insert (i + 1, e);
eErrCode = saveObjectAt (aDstNode, aDstNode.location());
if (eErrCode != store_E_None)
return eErrCode;
// Check for (not a) hardlink.
if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
{
// Modify 'Source' directory page.
inode_holder_type xNode (aPage.get());
// Setup 'Destination' NameBlock.
sal_Int32 nDstLen = pDstName->length;
memcpy (
&(xNode->m_aNameBlock.m_pData[0]),
pDstName->buffer, pDstName->length);
memset (
&(xNode->m_aNameBlock.m_pData[nDstLen]),
0, STORE_MAXIMUM_NAMESIZE - nDstLen);
aPage.key (e.m_aKey);
// Save directory page.
eErrCode = base::saveObjectAt (aPage, e.m_aLink.location());
if (eErrCode != store_E_None)
return eErrCode;
}
// Remove 'Source' entry.
e.m_aKey = rSrcKey;
return remove_Impl (e);
}
/*
* remove.
* Precond: initialized, writeable.
*/
storeError OStorePageManager::remove (const OStorePageKey &rKey)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check precond.
if (!self::isValid())
return store_E_InvalidAccess;
if (!base::isWriteable())
return store_E_AccessViolation;
// Find NodePage and index.
OStoreBTreeNodeObject aNodePage;
sal_uInt16 i = 0;
storeError eErrCode = find_lookup (aNodePage, i, rKey);
if (eErrCode != store_E_None)
return eErrCode;
// Existing entry.
PageHolderObject< page > xNodePage (aNodePage.get());
entry e (xNodePage->m_pData[i]);
// Check for (not a) hardlink.
if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
{
// Load directory page.
OStoreDirectoryPageObject aPage;
eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
if (eErrCode != store_E_None)
return eErrCode;
inode_holder_type xNode (aPage.get());
// Acquire page write access.
OStorePageDescriptor aDescr (xNode->m_aDescr);
eErrCode = base::acquirePage (aDescr, store_AccessReadWrite);
if (eErrCode != store_E_None)
return eErrCode;
// Check for symbolic link.
if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
{
// Ordinary inode. Determine 'Data' scope.
inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
if (eScope == inode::SCOPE_EXTERNAL)
{
// External 'Data' scope. Truncate all external data pages.
eErrCode = aPage.truncate (0, *this);
if (eErrCode != store_E_None)
return eErrCode;
}
// Truncate internal data page.
memset (&(xNode->m_pData[0]), 0, xNode->capacity());
aPage.dataLength (0);
}
// Release page write access.
eErrCode = base::releasePage (aDescr, store_AccessReadWrite);
// Release and free directory page.
eErrCode = base::free (aPage.location());
}
// Remove entry.
return remove_Impl (e);
}
/*
* RebuildContext.
*/
struct RebuildContext
{
/** Representation.
*/
rtl::Reference<OStorePageBIOS> m_xBIOS;
OStorePageBIOS::ScanContext m_aCtx;
sal_uInt16 m_nPageSize;
/** Construction.
*/
RebuildContext (void)
: m_xBIOS (new OStorePageBIOS()),
m_nPageSize (0)
{}
/** initialize (PageBIOS and ScanContext).
*/
storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0)
{
storeError eErrCode = store_E_InvalidParameter;
if (pLockBytes)
{
m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize);
eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic);
}
return eErrCode;
}
/** initialize (ScanContext).
*/
storeError initialize (sal_uInt32 nMagic = 0)
{
return m_xBIOS->scanBegin (m_aCtx, nMagic);
}
/** load (next ScanContext matching page).
*/
storeError load (OStorePageObject &rPage)
{
if (m_aCtx.isValid())
return m_xBIOS->scanNext (m_aCtx, rPage);
else
return store_E_CantSeek;
}
};
/*
* rebuild.
* Precond: none.
*/
storeError OStorePageManager::rebuild (
ILockBytes *pSrcLB, ILockBytes *pDstLB)
{
// Acquire exclusive access.
osl::MutexGuard aGuard(*this);
// Check arguments.
storeError eErrCode = store_E_InvalidParameter;
if (!(pSrcLB && pDstLB))
return eErrCode;
// Initialize 'Source' rebuild context.
RebuildContext aCtx;
eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE);
if (eErrCode != store_E_None)
return eErrCode;
rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS);
// Initialize as 'Destination' with 'Source' page size.
eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize);
if (eErrCode != store_E_None)
return eErrCode;
// Pass One: Scan 'Source' directory pages.
{
// Scan 'Source' directory pages.
OStoreDirectoryPageObject aSrcPage;
while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None)
{
OStoreDirectoryPageObject aDstPage;
eErrCode = aDstPage.construct< inode >(base::allocator());
if (eErrCode != store_E_None)
break;
inode_holder_type xSrcDir (aSrcPage.get());
inode_holder_type xDstDir (aDstPage.get());
// Copy NameBlock @@@ OLD @@@
memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock));
// Obtain 'Source' data length.
sal_uInt32 nDataLen = aSrcPage.dataLength();
if (nDataLen > 0)
{
// Copy internal data area @@@ OLD @@@
memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity());
}
// Insert 'Destination' directory page.
eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage);
if (eErrCode != store_E_None)
break;
// Check for external data page scope.
if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL)
{
// Initialize 'Destination' data page.
typedef OStoreDataPageData data;
PageHolderObject< data > xData;
if (!xData.construct(base::allocator()))
return store_E_OutOfMemory;
// Determine data page count.
inode::ChunkDescriptor aDescr (
nDataLen - xDstDir->capacity(), xData->capacity());
sal_uInt32 i, n = aDescr.m_nPage;
if (aDescr.m_nOffset) n += 1;
// Copy data pages.
OStoreDataPageObject aData;
for (i = 0; i < n; i++)
{
// Read 'Source' data page.
osl::MutexGuard aSrcGuard (*xSrcBIOS);
eErrCode = aSrcPage.read (i, aData, *xSrcBIOS);
if (eErrCode != store_E_None)
continue;
// Write 'Destination' data page. @@@ READONLY @@@
eErrCode = aDstPage.write (i, aData, *this);
}
}
// Update 'Destination' directory page.
aDstPage.dataLength (nDataLen);
eErrCode = base::saveObjectAt (aDstPage, aDstPage.location());
}
// Save directory scan results.
flush();
}
// Pass Two: Scan 'Source' BTree nodes.
{
// Re-start 'Source' rebuild context.
aCtx.initialize (STORE_MAGIC_BTREENODE);
// Scan 'Source' BTree nodes.
OStoreBTreeNodeObject aNode;
while ((eErrCode = aCtx.load(aNode)) == store_E_None)
{
// Check for leaf node.
PageHolderObject< page > xNode (aNode.get());
if (xNode->depth() == 0)
{
sal_uInt16 i, n = xNode->usageCount();
for (i = 0; i < n; i++)
{
entry e (xNode->m_pData[i]);
// Check for Hard link.
if (e.m_nAttrib & STORE_ATTRIB_ISLINK)
{
// Load the hard link destination.
OStoreDirectoryPageObject aSrcPage;
eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location());
if (eErrCode == store_E_None)
{
OStorePageKey aDstKey (aSrcPage.key());
eErrCode = link (e.m_aKey, aDstKey);
}
e.m_nAttrib &= ~STORE_ATTRIB_ISLINK;
}
if (e.m_nAttrib)
{
// Ordinary attributes.
sal_uInt32 nAttrib = 0;
eErrCode = attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib);
}
}
}
}
// Save BTree node scan results.
flush();
}
// Done.
return store_E_None;
}