summaryrefslogtreecommitdiffstats
path: root/store/source/storpage.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'store/source/storpage.cxx')
-rw-r--r--store/source/storpage.cxx509
1 files changed, 509 insertions, 0 deletions
diff --git a/store/source/storpage.cxx b/store/source/storpage.cxx
new file mode 100644
index 000000000..4eb9c2596
--- /dev/null
+++ b/store/source/storpage.cxx
@@ -0,0 +1,509 @@
+/* -*- 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 "storpage.hxx"
+
+#include <sal/types.h>
+#include <sal/log.hxx>
+#include <rtl/string.h>
+#include <osl/mutex.hxx>
+
+#include <store/types.h>
+
+#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()
+{
+}
+
+/*
+ * ~OStorePageManager.
+ */
+OStorePageManager::~OStorePageManager()
+{
+}
+
+/*
+ * isKindOf.
+ */
+bool 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());
+ SAL_WARN_IF(rIndex >= xPage->usageCount(), "store", "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.
+ */
+
+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]);
+ }
+
+ SAL_WARN_IF(
+ result == entry::COMPARE_LESS,
+ "store",
+ "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 == storeAccessMode::ReadWrite)
+ return store_E_NotExists;
+ if (eMode == storeAccessMode::ReadOnly)
+ 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());
+}
+
+/*
+ * 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, storeAccessMode::ReadWrite);
+ 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.
+ base::releasePage (aDescr);
+
+ // Release and free directory page.
+ (void)base::free (aPage.location());
+ }
+
+ // Remove entry.
+ return remove_Impl (e);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */