1106 lines
32 KiB
C++
1106 lines
32 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* 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.
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
#include "stordata.hxx"
|
|
|
|
#include "sal/types.h"
|
|
#include "osl/diagnose.h"
|
|
|
|
#include "store/types.h"
|
|
#include "storbase.hxx"
|
|
#include "storbios.hxx"
|
|
|
|
using namespace store;
|
|
|
|
/*========================================================================
|
|
*
|
|
* OStoreDataPageObject implementation.
|
|
*
|
|
*======================================================================*/
|
|
/*
|
|
* guard.
|
|
*/
|
|
storeError OStoreDataPageObject::guard (sal_uInt32 nAddr)
|
|
{
|
|
return PageHolderObject< page >::guard (m_xPage, nAddr);
|
|
}
|
|
|
|
/*
|
|
* verify.
|
|
*/
|
|
storeError OStoreDataPageObject::verify (sal_uInt32 nAddr) const
|
|
{
|
|
return PageHolderObject< page >::verify (m_xPage, nAddr);
|
|
}
|
|
|
|
/*========================================================================
|
|
*
|
|
* OStoreIndirectionPageObject implementation.
|
|
*
|
|
*======================================================================*/
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* loadOrCreate.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* guard.
|
|
*/
|
|
storeError OStoreIndirectionPageObject::guard (sal_uInt32 nAddr)
|
|
{
|
|
return PageHolderObject< page >::guard (m_xPage, nAddr);
|
|
}
|
|
|
|
/*
|
|
* verify.
|
|
*/
|
|
storeError OStoreIndirectionPageObject::verify (sal_uInt32 nAddr) const
|
|
{
|
|
return PageHolderObject< page >::verify (m_xPage, nAddr);
|
|
}
|
|
|
|
/*
|
|
* read (single indirect).
|
|
*/
|
|
storeError OStoreIndirectionPageObject::read (
|
|
sal_uInt16 nSingle,
|
|
OStoreDataPageObject &rData,
|
|
OStorePageBIOS &rBIOS)
|
|
{
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/*========================================================================
|
|
*
|
|
* OStoreDirectoryPageObject implementation.
|
|
*
|
|
*======================================================================*/
|
|
/*
|
|
* guard.
|
|
*/
|
|
storeError OStoreDirectoryPageObject::guard (sal_uInt32 nAddr)
|
|
{
|
|
return PageHolderObject< page >::guard (m_xPage, nAddr);
|
|
}
|
|
|
|
/*
|
|
* verify.
|
|
*/
|
|
storeError OStoreDirectoryPageObject::verify (sal_uInt32 nAddr) const
|
|
{
|
|
return PageHolderObject< page >::verify (m_xPage, nAddr);
|
|
// OLD: m_rPage.verifyVersion (STORE_MAGIC_DIRECTORYPAGE);
|
|
}
|
|
|
|
/*
|
|
* scope (external data page; private).
|
|
*/
|
|
OStoreDirectoryPageData::ChunkScope
|
|
OStoreDirectoryPageObject::scope (
|
|
sal_uInt32 nPage,
|
|
page::DataBlock::LinkDescriptor &rDescr) const
|
|
{
|
|
page const & rPage = PAGE();
|
|
OStoreDirectoryDataBlock const & rDataBlock = rPage.m_aDataBlock;
|
|
|
|
sal_uInt32 index0, index1, index2, index3;
|
|
|
|
// direct.
|
|
sal_uInt32 nCount = rDataBlock.directCount();
|
|
sal_uInt32 nLimit = nCount;
|
|
if (nPage < nLimit)
|
|
{
|
|
// Page to index reduction.
|
|
index0 = nPage;
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_DIRECT;
|
|
}
|
|
nPage -= nLimit;
|
|
|
|
// single indirect.
|
|
sal_uInt32 const nCapacity = indirect::capacityCount(rPage.m_aDescr);
|
|
nCount = rDataBlock.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;
|
|
OSL_POSTCOND(n == nPage, "wrong math on indirect indices");
|
|
if (n != nPage)
|
|
return page::SCOPE_UNKNOWN;
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
|
|
rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_SINGLE;
|
|
}
|
|
nPage -= nLimit;
|
|
|
|
// double indirect.
|
|
nCount = rDataBlock.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;
|
|
OSL_POSTCOND(n == nPage, "wrong math on double indirect indices");
|
|
if (n != nPage)
|
|
return page::SCOPE_UNKNOWN;
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
|
|
rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff);
|
|
rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_DOUBLE;
|
|
}
|
|
nPage -= nLimit;
|
|
|
|
// triple indirect.
|
|
nCount = rDataBlock.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.
|
|
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;
|
|
OSL_POSTCOND(n == nPage, "wrong math on triple indirect indices");
|
|
if (n != nPage)
|
|
return page::SCOPE_UNKNOWN;
|
|
|
|
// Setup LinkDescriptor indices.
|
|
rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
|
|
rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff);
|
|
rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff);
|
|
rDescr.m_nIndex3 = (sal_uInt16)(index3 & 0xffff);
|
|
|
|
// Done.
|
|
return page::SCOPE_TRIPLE;
|
|
}
|
|
|
|
// Unreachable (more than triple indirect).
|
|
return page::SCOPE_UNREACHABLE;
|
|
}
|
|
|
|
/*
|
|
* read (external data page).
|
|
*/
|
|
storeError OStoreDirectoryPageObject::read (
|
|
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)
|
|
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.
|
|
OSL_TRACE("OStoreDirectoryPageObject::get(): scope failed");
|
|
eErrCode = store_E_Unknown;
|
|
}
|
|
|
|
// Leave.
|
|
return eErrCode;
|
|
}
|
|
|
|
/*
|
|
* write (external data page).
|
|
*/
|
|
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.
|
|
OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed");
|
|
eErrCode = store_E_Unknown;
|
|
}
|
|
|
|
// Leave.
|
|
return eErrCode;
|
|
}
|
|
|
|
/*
|
|
* truncate (external data page).
|
|
*/
|
|
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.
|
|
OSL_TRACE("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)
|
|
{
|
|
OStoreDirectoryDataBlock const & rDataBlock = PAGE().m_aDataBlock;
|
|
|
|
// Enter.
|
|
storeError eErrCode = store_E_None;
|
|
if (eScope == page::SCOPE_DIRECT)
|
|
{
|
|
// Truncate direct data pages.
|
|
sal_uInt16 i, n = rDataBlock.directCount();
|
|
for (i = n; 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.
|
|
sal_uInt16 i, n = rDataBlock.singleCount();
|
|
for (i = n; 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.
|
|
sal_uInt16 i, n = rDataBlock.doubleCount();
|
|
for (i = n; 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.
|
|
sal_uInt16 i, n = rDataBlock.tripleCount();
|
|
for (i = n; 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: */
|