983aa4a107
Change-Id: I4b2582d3a7314d8752a56e83a4af7618b053abb5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128170 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
1043 lines
30 KiB
C++
1043 lines
30 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 "stordata.hxx"
|
|
|
|
#include <sal/types.h>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <store/types.h>
|
|
#include "storbase.hxx"
|
|
#include "storbios.hxx"
|
|
|
|
using namespace store;
|
|
|
|
storeError OStoreDataPageObject::guard (sal_uInt32 nAddr)
|
|
{
|
|
return PageHolderObject< page >::guard (m_xPage, nAddr);
|
|
}
|
|
|
|
storeError OStoreDataPageObject::verify (sal_uInt32 nAddr) const
|
|
{
|
|
return PageHolderObject< page >::verify (m_xPage, nAddr);
|
|
}
|
|
|
|
/**
|
|
store_truncate_Impl (single indirect page).
|
|
*/
|
|
static storeError store_truncate_Impl (
|
|
sal_uInt32 nAddr,
|
|
sal_uInt16 nSingle,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
if (nAddr != STORE_PAGE_NULL)
|
|
{
|
|
// Load single indirect page.
|
|
OStoreIndirectionPageObject aSingle;
|
|
storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr);
|
|
if (eErrCode == store_E_None)
|
|
{
|
|
// Truncate to 'nSingle' direct pages.
|
|
eErrCode = aSingle.truncate (nSingle, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
else
|
|
{
|
|
if (eErrCode != store_E_InvalidChecksum)
|
|
return eErrCode;
|
|
}
|
|
|
|
// Check for complete truncation.
|
|
if (nSingle == 0)
|
|
{
|
|
// Free single indirect page.
|
|
eErrCode = rBIOS.free (nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
}
|
|
return store_E_None;
|
|
}
|
|
|
|
/*
|
|
* store_truncate_Impl (double indirect page).
|
|
*/
|
|
static storeError store_truncate_Impl (
|
|
sal_uInt32 nAddr,
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
if (nAddr != STORE_PAGE_NULL)
|
|
{
|
|
// Load double indirect page.
|
|
OStoreIndirectionPageObject aDouble;
|
|
storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr);
|
|
if (eErrCode == store_E_None)
|
|
{
|
|
// Truncate to 'nDouble', 'nSingle' pages.
|
|
eErrCode = aDouble.truncate (nDouble, nSingle, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
else
|
|
{
|
|
if (eErrCode != store_E_InvalidChecksum)
|
|
return eErrCode;
|
|
}
|
|
|
|
// Check for complete truncation.
|
|
if ((nDouble + nSingle) == 0)
|
|
{
|
|
// Free double indirect page.
|
|
eErrCode = rBIOS.free (nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
}
|
|
return store_E_None;
|
|
}
|
|
|
|
/*
|
|
* store_truncate_Impl (triple indirect page).
|
|
*/
|
|
static storeError store_truncate_Impl (
|
|
sal_uInt32 nAddr,
|
|
sal_uInt16 nTriple,
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
if (nAddr != STORE_PAGE_NULL)
|
|
{
|
|
// Load triple indirect page.
|
|
OStoreIndirectionPageObject aTriple;
|
|
storeError eErrCode = rBIOS.loadObjectAt (aTriple, nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate to 'nTriple', 'nDouble', 'nSingle' pages.
|
|
eErrCode = aTriple.truncate (nTriple, nDouble, nSingle, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Check for complete truncation.
|
|
if ((nTriple + nDouble + nSingle) == 0)
|
|
{
|
|
// Free triple indirect page.
|
|
eErrCode = rBIOS.free (nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
}
|
|
return store_E_None;
|
|
}
|
|
|
|
storeError OStoreIndirectionPageObject::loadOrCreate (
|
|
sal_uInt32 nAddr,
|
|
OStorePageBIOS & rBIOS)
|
|
{
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
{
|
|
storeError eErrCode = construct<page>(rBIOS.allocator());
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
eErrCode = rBIOS.allocate (*this);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Save location pending at caller.
|
|
return store_E_Pending;
|
|
}
|
|
return rBIOS.loadObjectAt (*this, nAddr);
|
|
}
|
|
|
|
storeError OStoreIndirectionPageObject::guard (sal_uInt32 nAddr)
|
|
{
|
|
return PageHolderObject< page >::guard (m_xPage, nAddr);
|
|
}
|
|
|
|
storeError OStoreIndirectionPageObject::verify (sal_uInt32 nAddr) const
|
|
{
|
|
return PageHolderObject< page >::verify (m_xPage, nAddr);
|
|
}
|
|
|
|
storeError OStoreIndirectionPageObject::read (
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS) const
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page const & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if (nSingle >= nLimit)
|
|
return store_E_InvalidAccess;
|
|
|
|
// Obtain data page location.
|
|
sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
// Load data page and leave.
|
|
return rBIOS.loadObjectAt (rData, nAddr);
|
|
}
|
|
|
|
/*
|
|
* read (double indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::read (
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS) const
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page const & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if ((nDouble >= nLimit) || (nSingle >= nLimit))
|
|
return store_E_InvalidAccess;
|
|
|
|
// Check single indirect page location.
|
|
sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nDouble]);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
// Load single indirect page.
|
|
OStoreIndirectionPageObject aSingle;
|
|
storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Read single indirect and leave.
|
|
return aSingle.read (nSingle, rData, rBIOS);
|
|
}
|
|
|
|
/*
|
|
* read (triple indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::read (
|
|
sal_uInt16 nTriple,
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS) const
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page const & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit)))
|
|
return store_E_InvalidAccess;
|
|
|
|
// Check double indirect page location.
|
|
sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nTriple]);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
// Load double indirect page.
|
|
OStoreIndirectionPageObject aDouble;
|
|
storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Read double indirect and leave.
|
|
return aDouble.read (nDouble, nSingle, rData, rBIOS);
|
|
}
|
|
|
|
/*
|
|
* write (single indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::write (
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if (nSingle >= nLimit)
|
|
return store_E_InvalidAccess;
|
|
|
|
// Obtain data page location.
|
|
sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
{
|
|
// Allocate data page.
|
|
storeError eErrCode = rBIOS.allocate (rData);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Store data page location.
|
|
rPage.m_pData[nSingle] = store::htonl(rData.location());
|
|
|
|
// Save this page.
|
|
return rBIOS.saveObjectAt (*this, location());
|
|
}
|
|
else
|
|
{
|
|
// Save data page.
|
|
return rBIOS.saveObjectAt (rData, nAddr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* write (double indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::write (
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if ((nDouble >= nLimit) || (nSingle >= nLimit))
|
|
return store_E_InvalidAccess;
|
|
|
|
// Load or create single indirect page.
|
|
OStoreIndirectionPageObject aSingle;
|
|
storeError eErrCode = aSingle.loadOrCreate (store::ntohl(rPage.m_pData[nDouble]), rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
{
|
|
if (eErrCode != store_E_Pending)
|
|
return eErrCode;
|
|
rPage.m_pData[nDouble] = store::htonl(aSingle.location());
|
|
|
|
eErrCode = rBIOS.saveObjectAt (*this, location());
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
|
|
// Write single indirect and leave.
|
|
return aSingle.write (nSingle, rData, rBIOS);
|
|
}
|
|
|
|
/*
|
|
* write (triple indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::write (
|
|
sal_uInt16 nTriple,
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit)))
|
|
return store_E_InvalidAccess;
|
|
|
|
// Load or create double indirect page.
|
|
OStoreIndirectionPageObject aDouble;
|
|
storeError eErrCode = aDouble.loadOrCreate (store::ntohl(rPage.m_pData[nTriple]), rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
{
|
|
if (eErrCode != store_E_Pending)
|
|
return eErrCode;
|
|
rPage.m_pData[nTriple] = store::htonl(aDouble.location());
|
|
|
|
eErrCode = rBIOS.saveObjectAt (*this, location());
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
}
|
|
|
|
// Write double indirect and leave.
|
|
return aDouble.write (nDouble, nSingle, rData, rBIOS);
|
|
}
|
|
|
|
/*
|
|
* truncate (single indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::truncate (
|
|
sal_uInt16 nSingle,
|
|
OStorePageBIOS & rBIOS)
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if (nSingle >= nLimit)
|
|
return store_E_InvalidAccess;
|
|
|
|
// Truncate.
|
|
storeError eErrCode = store_E_None;
|
|
for (sal_uInt16 i = nLimit; i > nSingle; i--)
|
|
{
|
|
// Obtain data page location.
|
|
sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[i - 1]);
|
|
if (nAddr != STORE_PAGE_NULL)
|
|
{
|
|
// Free data page.
|
|
eErrCode = rBIOS.free (nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Clear pointer to data page.
|
|
rPage.m_pData[i - 1] = STORE_PAGE_NULL;
|
|
touch();
|
|
}
|
|
}
|
|
|
|
// Check for modified page.
|
|
if (dirty())
|
|
{
|
|
// Save this page.
|
|
eErrCode = rBIOS.saveObjectAt (*this, location());
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
/*
|
|
* truncate (double indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::truncate (
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if ((nDouble >= nLimit) || (nSingle >= nLimit))
|
|
return store_E_InvalidAccess;
|
|
|
|
// Truncate.
|
|
storeError eErrCode = store_E_None;
|
|
for (sal_uInt16 i = nLimit; i > nDouble + 1; i--)
|
|
{
|
|
// Truncate single indirect page to zero direct pages.
|
|
eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Clear pointer to single indirect page.
|
|
rPage.m_pData[i - 1] = STORE_PAGE_NULL;
|
|
touch();
|
|
}
|
|
|
|
// Truncate last single indirect page to 'nSingle' direct pages.
|
|
eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nDouble]), nSingle, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Check for complete truncation.
|
|
if (nSingle == 0)
|
|
{
|
|
// Clear pointer to last single indirect page.
|
|
rPage.m_pData[nDouble] = STORE_PAGE_NULL;
|
|
touch();
|
|
}
|
|
|
|
// Check for modified page.
|
|
if (dirty())
|
|
{
|
|
// Save this page.
|
|
eErrCode = rBIOS.saveObjectAt (*this, location());
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
/*
|
|
* truncate (triple indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::truncate (
|
|
sal_uInt16 nTriple,
|
|
sal_uInt16 nDouble,
|
|
sal_uInt16 nSingle,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
PageHolderObject< page > xImpl (m_xPage);
|
|
page & rPage = *xImpl;
|
|
|
|
// Check arguments.
|
|
sal_uInt16 const nLimit = rPage.capacityCount();
|
|
if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit)))
|
|
return store_E_InvalidAccess;
|
|
|
|
// Truncate.
|
|
storeError eErrCode = store_E_None;
|
|
for (sal_uInt16 i = nLimit; i > nTriple + 1; i--)
|
|
{
|
|
// Truncate double indirect page to zero single indirect pages.
|
|
eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Clear pointer to double indirect page.
|
|
rPage.m_pData[i - 1] = STORE_PAGE_NULL;
|
|
touch();
|
|
}
|
|
|
|
// Truncate last double indirect page to 'nDouble', 'nSingle' pages.
|
|
eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nTriple]), nDouble, nSingle, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Check for complete truncation.
|
|
if ((nDouble + nSingle) == 0)
|
|
{
|
|
// Clear pointer to last double indirect page.
|
|
rPage.m_pData[nTriple] = STORE_PAGE_NULL;
|
|
touch();
|
|
}
|
|
|
|
// Check for modified page.
|
|
if (dirty())
|
|
{
|
|
// Save this page.
|
|
eErrCode = rBIOS.saveObjectAt (*this, location());
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
storeError OStoreDirectoryPageObject::guard (sal_uInt32 nAddr)
|
|
{
|
|
return PageHolderObject< page >::guard (m_xPage, nAddr);
|
|
}
|
|
|
|
storeError OStoreDirectoryPageObject::verify (sal_uInt32 nAddr) const
|
|
{
|
|
return PageHolderObject< page >::verify (m_xPage, nAddr);
|
|
}
|
|
|
|
OStoreDirectoryPageData::ChunkScope
|
|
OStoreDirectoryPageObject::scope (
|
|
sal_uInt32 nPage,
|
|
page::DataBlock::LinkDescriptor &rDescr) const
|
|
{
|
|
page const & rPage = PAGE();
|
|
|
|
sal_uInt32 index0, index1, index2;
|
|
|
|
// direct.
|
|
sal_uInt32 nCount = OStoreDirectoryDataBlock::directCount;
|
|
sal_uInt32 nLimit = nCount;
|
|
if (nPage < nLimit)
|
|
{
|
|
// Page to index reduction.
|
|
index0 = nPage;
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = static_cast<sal_uInt16>(index0 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_DIRECT;
|
|
}
|
|
nPage -= nLimit;
|
|
|
|
// single indirect.
|
|
sal_uInt32 const nCapacity = indirect::capacityCount(rPage.m_aDescr);
|
|
nCount = OStoreDirectoryDataBlock::singleCount;
|
|
nLimit = nCount * nCapacity;
|
|
if (nPage < nLimit)
|
|
{
|
|
// Page to index reduction.
|
|
sal_uInt32 n = nPage;
|
|
|
|
// Reduce to single indirect i(1), direct n = i(0).
|
|
index1 = n / nCapacity;
|
|
index0 = n % nCapacity;
|
|
|
|
// Verify reduction.
|
|
n = index1 * nCapacity + index0;
|
|
if (n != nPage)
|
|
{
|
|
SAL_WARN("store", "wrong math on indirect indices");
|
|
return page::SCOPE_UNKNOWN;
|
|
}
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = static_cast<sal_uInt16>(index0 & 0xffff);
|
|
rDescr.m_nIndex1 = static_cast<sal_uInt16>(index1 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_SINGLE;
|
|
}
|
|
nPage -= nLimit;
|
|
|
|
// double indirect.
|
|
nCount = OStoreDirectoryDataBlock::doubleCount;
|
|
nLimit = nCount * nCapacity * nCapacity;
|
|
if (nPage < nLimit)
|
|
{
|
|
// Page to index reduction.
|
|
sal_uInt32 n = nPage;
|
|
|
|
// Reduce to double indirect i(2), single indirect n = i(0).
|
|
index2 = n / (nCapacity * nCapacity);
|
|
n = n % (nCapacity * nCapacity);
|
|
|
|
// Reduce to single indirect i(1), direct n = i(0).
|
|
index1 = n / nCapacity;
|
|
index0 = n % nCapacity;
|
|
|
|
// Verify reduction.
|
|
n = index2 * nCapacity * nCapacity +
|
|
index1 * nCapacity + index0;
|
|
if (n != nPage)
|
|
{
|
|
SAL_WARN("store", "wrong math on double indirect indices");
|
|
return page::SCOPE_UNKNOWN;
|
|
}
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = static_cast<sal_uInt16>(index0 & 0xffff);
|
|
rDescr.m_nIndex1 = static_cast<sal_uInt16>(index1 & 0xffff);
|
|
rDescr.m_nIndex2 = static_cast<sal_uInt16>(index2 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_DOUBLE;
|
|
}
|
|
nPage -= nLimit;
|
|
|
|
// triple indirect.
|
|
nCount = OStoreDirectoryDataBlock::tripleCount;
|
|
nLimit = nCount * nCapacity * nCapacity * nCapacity;
|
|
if (nPage < nLimit)
|
|
{
|
|
// Page to index reduction.
|
|
sal_uInt32 n = nPage;
|
|
|
|
// Reduce to triple indirect i(3), double indirect n.
|
|
sal_uInt32 index3 = n / (nCapacity * nCapacity * nCapacity);
|
|
n = n % (nCapacity * nCapacity * nCapacity);
|
|
|
|
// Reduce to double indirect i(2), single indirect n.
|
|
index2 = n / (nCapacity * nCapacity);
|
|
n = n % (nCapacity * nCapacity);
|
|
|
|
// Reduce to single indirect i(1), direct n = i(0).
|
|
index1 = n / nCapacity;
|
|
index0 = n % nCapacity;
|
|
|
|
// Verify reduction.
|
|
n = index3 * nCapacity * nCapacity * nCapacity +
|
|
index2 * nCapacity * nCapacity +
|
|
index1 * nCapacity + index0;
|
|
if (n != nPage)
|
|
{
|
|
SAL_WARN("store", "wrong math on triple indirect indices");
|
|
return page::SCOPE_UNKNOWN;
|
|
}
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = static_cast<sal_uInt16>(index0 & 0xffff);
|
|
rDescr.m_nIndex1 = static_cast<sal_uInt16>(index1 & 0xffff);
|
|
rDescr.m_nIndex2 = static_cast<sal_uInt16>(index2 & 0xffff);
|
|
rDescr.m_nIndex3 = static_cast<sal_uInt16>(index3 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_TRIPLE;
|
|
}
|
|
|
|
// Unreachable (more than triple indirect).
|
|
return page::SCOPE_UNREACHABLE;
|
|
}
|
|
|
|
storeError OStoreDirectoryPageObject::read (
|
|
sal_uInt32 nPage,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS) const
|
|
{
|
|
// Determine scope and link indices.
|
|
page::DataBlock::LinkDescriptor aLink;
|
|
page::ChunkScope eScope = scope (nPage, aLink);
|
|
|
|
storeError eErrCode = store_E_None;
|
|
if (eScope == page::SCOPE_DIRECT)
|
|
{
|
|
sal_uInt32 const nAddr = directLink (aLink.m_nIndex0);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
eErrCode = rBIOS.loadObjectAt (rData, nAddr);
|
|
}
|
|
else if (eScope == page::SCOPE_SINGLE)
|
|
{
|
|
sal_uInt32 const nAddr = singleLink (aLink.m_nIndex1);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
OStoreIndirectionPageObject aSingle;
|
|
eErrCode = rBIOS.loadObjectAt (aSingle, nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
eErrCode = aSingle.read (aLink.m_nIndex0, rData, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_DOUBLE)
|
|
{
|
|
sal_uInt32 const nAddr = doubleLink (aLink.m_nIndex2);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
OStoreIndirectionPageObject aDouble;
|
|
eErrCode = rBIOS.loadObjectAt (aDouble, nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
eErrCode = aDouble.read (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_TRIPLE)
|
|
{
|
|
sal_uInt32 const nAddr = tripleLink (aLink.m_nIndex3);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
return store_E_NotExists;
|
|
|
|
OStoreIndirectionPageObject aTriple;
|
|
eErrCode = rBIOS.loadObjectAt (aTriple, nAddr);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
eErrCode = aTriple.read (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_UNREACHABLE)
|
|
{
|
|
// Out of scope.
|
|
eErrCode = store_E_CantSeek;
|
|
}
|
|
else
|
|
{
|
|
// Unknown scope.
|
|
SAL_WARN("store", "OStoreDirectoryPageObject::get(): scope failed");
|
|
eErrCode = store_E_Unknown;
|
|
}
|
|
|
|
// Leave.
|
|
return eErrCode;
|
|
}
|
|
|
|
storeError OStoreDirectoryPageObject::write (
|
|
sal_uInt32 nPage,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
// Determine scope and link indices.
|
|
page::DataBlock::LinkDescriptor aLink;
|
|
page::ChunkScope eScope = scope (nPage, aLink);
|
|
|
|
storeError eErrCode = store_E_None;
|
|
if (eScope == page::SCOPE_DIRECT)
|
|
{
|
|
sal_uInt32 const nAddr = directLink (aLink.m_nIndex0);
|
|
if (nAddr == STORE_PAGE_NULL)
|
|
{
|
|
// Allocate data page.
|
|
eErrCode = rBIOS.allocate (rData);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Store data page location.
|
|
directLink (aLink.m_nIndex0, rData.location());
|
|
}
|
|
else
|
|
{
|
|
// Save data page.
|
|
eErrCode = rBIOS.saveObjectAt (rData, nAddr);
|
|
}
|
|
}
|
|
else if (eScope == page::SCOPE_SINGLE)
|
|
{
|
|
OStoreIndirectionPageObject aSingle;
|
|
eErrCode = aSingle.loadOrCreate (singleLink (aLink.m_nIndex1), rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
{
|
|
if (eErrCode != store_E_Pending)
|
|
return eErrCode;
|
|
singleLink (aLink.m_nIndex1, aSingle.location());
|
|
}
|
|
|
|
eErrCode = aSingle.write (aLink.m_nIndex0, rData, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_DOUBLE)
|
|
{
|
|
OStoreIndirectionPageObject aDouble;
|
|
eErrCode = aDouble.loadOrCreate (doubleLink (aLink.m_nIndex2), rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
{
|
|
if (eErrCode != store_E_Pending)
|
|
return eErrCode;
|
|
doubleLink (aLink.m_nIndex2, aDouble.location());
|
|
}
|
|
|
|
eErrCode = aDouble.write (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_TRIPLE)
|
|
{
|
|
OStoreIndirectionPageObject aTriple;
|
|
eErrCode = aTriple.loadOrCreate (tripleLink (aLink.m_nIndex3), rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
{
|
|
if (eErrCode != store_E_Pending)
|
|
return eErrCode;
|
|
tripleLink (aLink.m_nIndex3, aTriple.location());
|
|
}
|
|
|
|
eErrCode = aTriple.write (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_UNREACHABLE)
|
|
{
|
|
// Out of scope.
|
|
eErrCode = store_E_CantSeek;
|
|
}
|
|
else
|
|
{
|
|
// Unknown scope.
|
|
SAL_WARN("store", "OStoreDirectoryPageObject::put(): scope failed");
|
|
eErrCode = store_E_Unknown;
|
|
}
|
|
|
|
// Leave.
|
|
return eErrCode;
|
|
}
|
|
|
|
storeError OStoreDirectoryPageObject::truncate (
|
|
sal_uInt32 nPage,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
// Determine scope and link indices.
|
|
page::DataBlock::LinkDescriptor aLink;
|
|
page::ChunkScope eScope = scope (nPage, aLink);
|
|
|
|
storeError eErrCode = store_E_None;
|
|
if (eScope == page::SCOPE_DIRECT)
|
|
{
|
|
// Truncate all triple indirect pages.
|
|
eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate all double indirect pages.
|
|
eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate all single indirect pages.
|
|
eErrCode = truncate (page::SCOPE_SINGLE, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate direct pages, including 'aLink.m_nIndex0'.
|
|
eErrCode = truncate (eScope, aLink.m_nIndex0, rBIOS);
|
|
}
|
|
else if (eScope == page::SCOPE_SINGLE)
|
|
{
|
|
// Truncate all triple indirect pages.
|
|
eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate all double indirect pages.
|
|
eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate single indirect pages, downto 'aLink.m_nIndex1'.
|
|
eErrCode = truncate (eScope, aLink.m_nIndex1 + 1, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate last single indirect page to ... pages.
|
|
eErrCode = store_truncate_Impl (singleLink (aLink.m_nIndex1), aLink.m_nIndex0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Check for complete truncation.
|
|
if (aLink.m_nIndex0 == 0)
|
|
{
|
|
// Clear pointer to last single indirect page.
|
|
singleLink (aLink.m_nIndex1, STORE_PAGE_NULL);
|
|
}
|
|
}
|
|
else if (eScope == page::SCOPE_DOUBLE)
|
|
{
|
|
// Truncate all triple indirect pages.
|
|
eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate double indirect pages, downto 'aLink.m_nIndex2'.
|
|
eErrCode = truncate (eScope, aLink.m_nIndex2 + 1, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate last double indirect page to ... pages.
|
|
eErrCode = store_truncate_Impl (
|
|
doubleLink (aLink.m_nIndex2), aLink.m_nIndex1, aLink.m_nIndex0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Check for complete truncation.
|
|
if ((aLink.m_nIndex1 + aLink.m_nIndex0) == 0)
|
|
{
|
|
// Clear pointer to last double indirect page.
|
|
doubleLink (aLink.m_nIndex2, STORE_PAGE_NULL);
|
|
}
|
|
}
|
|
else if (eScope == page::SCOPE_TRIPLE)
|
|
{
|
|
// Truncate triple indirect pages, downto 'aLink.m_nIndex3'.
|
|
eErrCode = truncate (eScope, aLink.m_nIndex3 + 1, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Truncate last triple indirect page to ... pages.
|
|
eErrCode = store_truncate_Impl (
|
|
tripleLink (aLink.m_nIndex3), aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
return eErrCode;
|
|
|
|
// Check for complete truncation.
|
|
if ((aLink.m_nIndex2 + aLink.m_nIndex1 + aLink.m_nIndex0) == 0)
|
|
{
|
|
// Clear pointer to last triple indirect page.
|
|
tripleLink (aLink.m_nIndex3, STORE_PAGE_NULL);
|
|
}
|
|
}
|
|
else if (eScope == page::SCOPE_UNREACHABLE)
|
|
{
|
|
// Out of scope.
|
|
eErrCode = store_E_CantSeek;
|
|
}
|
|
else
|
|
{
|
|
// Unknown scope.
|
|
SAL_WARN("store", "OStoreDirectoryPageObject::put(): scope failed");
|
|
eErrCode = store_E_Unknown;
|
|
}
|
|
|
|
// Leave.
|
|
return eErrCode;
|
|
}
|
|
|
|
/*
|
|
* truncate (external data page scope; private).
|
|
*/
|
|
storeError OStoreDirectoryPageObject::truncate (
|
|
page::ChunkScope eScope,
|
|
sal_uInt16 nRemain,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
// Enter.
|
|
storeError eErrCode = store_E_None;
|
|
if (eScope == page::SCOPE_DIRECT)
|
|
{
|
|
// Truncate direct data pages.
|
|
for (sal_uInt16 i = OStoreDirectoryDataBlock::directCount; i > nRemain; i--)
|
|
{
|
|
// Obtain data page location.
|
|
sal_uInt32 nAddr = directLink (i - 1);
|
|
if (nAddr == STORE_PAGE_NULL) continue;
|
|
|
|
// Free data page.
|
|
eErrCode = rBIOS.free (nAddr);
|
|
if (eErrCode != store_E_None)
|
|
break;
|
|
|
|
// Clear pointer to data page.
|
|
directLink (i - 1, STORE_PAGE_NULL);
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
if (eScope == page::SCOPE_SINGLE)
|
|
{
|
|
// Truncate single indirect pages.
|
|
for (sal_uInt16 i = OStoreDirectoryDataBlock::singleCount; i > nRemain; i--)
|
|
{
|
|
// Truncate single indirect page to zero data pages.
|
|
eErrCode = store_truncate_Impl (singleLink (i - 1), 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
break;
|
|
|
|
// Clear pointer to single indirect page.
|
|
singleLink (i - 1, STORE_PAGE_NULL);
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
if (eScope == page::SCOPE_DOUBLE)
|
|
{
|
|
// Truncate double indirect pages.
|
|
for (sal_uInt16 i = OStoreDirectoryDataBlock::doubleCount; i > nRemain; i--)
|
|
{
|
|
// Truncate double indirect page to zero single indirect pages.
|
|
eErrCode = store_truncate_Impl (doubleLink (i - 1), 0, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
break;
|
|
|
|
// Clear pointer to double indirect page.
|
|
doubleLink (i - 1, STORE_PAGE_NULL);
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
if (eScope == page::SCOPE_TRIPLE)
|
|
{
|
|
// Truncate triple indirect pages.
|
|
for (sal_uInt16 i = OStoreDirectoryDataBlock::tripleCount; i > nRemain; i--)
|
|
{
|
|
// Truncate to zero double indirect pages.
|
|
eErrCode = store_truncate_Impl (tripleLink (i - 1), 0, 0, 0, rBIOS);
|
|
if (eErrCode != store_E_None)
|
|
break;
|
|
|
|
// Clear pointer to triple indirect page.
|
|
tripleLink (i - 1, STORE_PAGE_NULL);
|
|
}
|
|
|
|
// Done.
|
|
return eErrCode;
|
|
}
|
|
|
|
// Invalid scope.
|
|
return store_E_InvalidAccess;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|