diff options
Diffstat (limited to 'store/source/storpage.cxx')
-rw-r--r-- | store/source/storpage.cxx | 1057 |
1 files changed, 1057 insertions, 0 deletions
diff --git a/store/source/storpage.cxx b/store/source/storpage.cxx new file mode 100644 index 000000000000..a49e850061b6 --- /dev/null +++ b/store/source/storpage.cxx @@ -0,0 +1,1057 @@ +/************************************************************************* + * + * 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; +} |