office-gobmx/store/source/storlckb.cxx
2001-03-13 20:07:32 +00:00

872 lines
23 KiB
C++

/*************************************************************************
*
* $RCSfile: storlckb.cxx,v $
*
* $Revision: 1.2 $
*
* last change: $Author: mhu $ $Date: 2001-03-13 21:03:26 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (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.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): Matthias Huetsch <matthias.huetsch@sun.com>
*
*
************************************************************************/
#define _STORE_STORLCKB_CXX_ "$Revision: 1.2 $"
#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif
#ifndef _SAL_MACROS_H_
#include <sal/macros.h>
#endif
#ifndef _RTL_MEMORY_H_
#include <rtl/memory.h>
#endif
#ifndef _RTL_TEXTCVT_H_
#include <rtl/textcvt.h>
#endif
#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif
#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif
#ifndef _STORE_TYPES_H_
#include <store/types.h>
#endif
#ifndef _STORE_OBJECT_HXX_
#include <store/object.hxx>
#endif
#ifndef _STORE_LOCKBYTE_HXX_
#include <store/lockbyte.hxx>
#endif
#ifndef _STORE_STORBASE_HXX_
#include <storbase.hxx>
#endif
#ifndef _STORE_STORDATA_HXX_
#include <stordata.hxx>
#endif
#ifndef _STORE_STORPAGE_HXX_
#include <storpage.hxx>
#endif
#ifndef _STORE_STORLCKB_HXX_
#include <storlckb.hxx>
#endif
using namespace store;
/*========================================================================
*
* OStore... internals.
*
*======================================================================*/
/*
* __store_convertTextToUnicode.
*/
inline sal_Int32 __store_convertTextToUnicode (
rtl_TextToUnicodeConverter hConverter,
const sal_Char *pSrcBuffer, sal_Int32 nSrcLength,
sal_Unicode *pDstBuffer, sal_Int32 nDstLength)
{
sal_uInt32 nCvtInfo, nCvtBytes = 0;
return rtl_convertTextToUnicode (
hConverter, 0,
pSrcBuffer, nSrcLength,
pDstBuffer, nDstLength,
OSTRING_TO_OUSTRING_CVTFLAGS,
&nCvtInfo, &nCvtBytes);
}
/*
* __store_iget.
* Precond: exclusive access.
*/
static storeError __store_iget (
OStorePageManager &rManager,
OStoreDirectoryPageData &rNode,
sal_uInt32 nAttrib,
const rtl_String *pPath,
const rtl_String *pName,
storeAccessMode eMode)
{
// Setup inode page key.
OStorePageKey aKey;
storeError eErrCode = OStorePageNameBlock::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 = OStorePageGuard::crc32 (aKey.m_nLow, "/", 1);
}
// Load inode page.
OStoreDirectoryPageObject aPage (rNode);
eErrCode = rManager.load (aKey, aPage);
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 (!rManager.isWriteable())
return store_E_AccessViolation;
// Setup inode nameblock.
rNode.m_aNameBlock.m_aKey = aKey;
rNode.m_aNameBlock.m_nAttrib = nAttrib;
rtl_copyMemory (
&rNode.m_aNameBlock.m_pData[0],
pName->buffer, pName->length);
// Save inode page.
eErrCode = rManager.save (aKey, aPage);
if (eErrCode != store_E_None)
return eErrCode;
}
// Check for symbolic link.
if (aPage.attrib() & STORE_ATTRIB_ISLINK)
{
// Obtain 'Destination' page key.
OStorePageKey aDstKey;
rtl_copyMemory (&aDstKey, &rNode.m_pData[0], sizeof(aDstKey));
#ifdef OSL_BIGENDIAN
// Swap to internal representation.
aDstKey.swap();
#endif /* OSL_BIGENDIAN */
// Load 'Destination' inode.
eErrCode = rManager.load (aDstKey, aPage);
if (eErrCode != store_E_None)
return eErrCode;
}
// Done.
return store_E_None;
}
/*========================================================================
*
* OStoreDirectory implementation.
*
*======================================================================*/
const sal_uInt32 OStoreDirectory::m_nTypeId = sal_uInt32(0x89191107);
/*
* OStoreDirectory.
*/
OStoreDirectory::OStoreDirectory (void)
: m_xManager (NULL),
m_pNode (NULL),
m_aDescr (0, 0, 0),
m_nPath (0),
m_hTextCvt (NULL)
{
}
/*
* ~OStoreDirectory.
*/
OStoreDirectory::~OStoreDirectory (void)
{
if (m_xManager.is())
{
osl::MutexGuard aGuard (*m_xManager);
if (m_pNode)
{
m_xManager->releasePage (m_aDescr, store_AccessReadOnly);
}
}
delete m_pNode;
rtl_destroyTextToUnicodeConverter (m_hTextCvt);
}
/*
* isKindOf.
*/
sal_Bool SAL_CALL OStoreDirectory::isKindOf (sal_uInt32 nTypeId)
{
return (nTypeId == m_nTypeId);
}
/*
* create.
*/
storeError OStoreDirectory::create (
OStorePageManager *pManager,
rtl_uString *pPath,
rtl_uString *pName,
storeAccessMode eMode)
{
rtl::Reference<OStorePageManager> xManager (pManager);
if (!xManager.is())
return store_E_InvalidAccess;
if (!(pPath && pName))
return store_E_InvalidParameter;
osl::MutexGuard aGuard (*xManager);
storeError eErrCode = xManager->getPageSize (m_aDescr.m_nSize);
if (eErrCode != store_E_None)
return eErrCode;
delete m_pNode;
m_pNode = new(m_aDescr.m_nSize) inode(m_aDescr.m_nSize);
if (!m_pNode)
return store_E_OutOfMemory;
rtl::OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8);
rtl::OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8);
eErrCode = __store_iget (
*xManager, *m_pNode, STORE_ATTRIB_ISDIR,
aPath.pData, aName.pData, eMode);
if (eErrCode != store_E_None)
return eErrCode;
sal_uInt32 nAttrib = m_pNode->m_aNameBlock.m_nAttrib;
if (!(nAttrib & STORE_ATTRIB_ISDIR))
return store_E_NotDirectory;
m_aDescr = m_pNode->m_aDescr;
eErrCode = xManager->acquirePage (m_aDescr, store_AccessReadOnly);
if (eErrCode == store_E_None)
{
// Evaluate iteration path from NameBlock.
typedef OStorePageGuard G;
sal_Char *pszName = m_pNode->m_aNameBlock.m_pData;
m_nPath = m_pNode->m_aNameBlock.m_aKey.m_nHigh;
m_nPath = G::crc32 (m_nPath, pszName, rtl_str_getLength(pszName));
m_nPath = G::crc32 (m_nPath, "/", 1);
// Accept page manager.
m_xManager = xManager;
}
return eErrCode;
}
/*
* iterate.
*/
storeError OStoreDirectory::iterate (storeFindData &rFindData)
{
if (!m_xManager.is())
return store_E_InvalidAccess;
storeError eErrCode = store_E_NoMoreFiles;
if (!rFindData.m_nReserved)
return eErrCode;
// Acquire exclusive access.
osl::MutexGuard aGuard (*m_xManager);
// Check TextConverter.
if (m_hTextCvt == NULL)
m_hTextCvt = rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_UTF8);
// Setup iteration key and page buffer.
OStorePageKey aKey (rFindData.m_nReserved, m_nPath);
OStoreDirectoryPageObject aPage (*m_pNode);
// Iterate.
for (;;)
{
eErrCode = m_xManager->iterate (aKey, aPage, rFindData.m_nAttrib);
if (!((eErrCode == store_E_None) && (aKey.m_nHigh == m_nPath)))
break;
if (!(rFindData.m_nAttrib & STORE_ATTRIB_ISLINK))
{
// Load page.
eErrCode = m_xManager->load (aPage);
if (eErrCode == store_E_None)
{
// Setup FindData.
sal_Char *p = m_pNode->m_aNameBlock.m_pData;
sal_Int32 n = rtl_str_getLength (p);
sal_Int32 k = rFindData.m_nLength;
n = __store_convertTextToUnicode (
m_hTextCvt, p, n,
rFindData.m_pszName, STORE_MAXIMUM_NAMESIZE - 1);
if (k > n)
{
k = (k - n) * sizeof(sal_Unicode);
rtl_zeroMemory (&rFindData.m_pszName[n], k);
}
rFindData.m_nLength = n;
rFindData.m_nAttrib |= aPage.attrib();
rFindData.m_nSize = aPage.dataLength();
// Leave.
rFindData.m_nReserved = aKey.m_nLow;
return store_E_None;
}
}
if (aKey.m_nLow > 0)
aKey.m_nLow -= 1;
else
break;
}
// Finished.
rtl_zeroMemory (&rFindData, sizeof (storeFindData));
return store_E_NoMoreFiles;
}
/*========================================================================
*
* OStoreLockBytes implementation.
*
*======================================================================*/
const sal_uInt32 OStoreLockBytes::m_nTypeId = sal_uInt32(0x94190310);
/*
* OStoreLockBytes.
*/
OStoreLockBytes::OStoreLockBytes (void)
: m_xManager (NULL),
m_nPageSize (0),
m_pNode (NULL),
m_pData (NULL),
m_pSingle (NULL),
m_pDouble (NULL),
m_pTriple (NULL),
m_bWriteable (sal_False)
{
}
/*
* ~OStoreLockBytes.
*/
OStoreLockBytes::~OStoreLockBytes (void)
{
if (m_xManager.is())
{
osl::MutexGuard aGuard (*m_xManager);
if (m_pNode)
{
OStorePageDescriptor aDescr (m_pNode->m_aDescr);
if (m_bWriteable)
m_xManager->releasePage (aDescr, store_AccessReadWrite);
else
m_xManager->releasePage (aDescr, store_AccessReadOnly);
}
}
delete m_pNode;
delete m_pData;
delete m_pSingle;
delete m_pDouble;
delete m_pTriple;
}
/*
* isKindOf.
*/
sal_Bool SAL_CALL OStoreLockBytes::isKindOf (sal_uInt32 nTypeId)
{
return (nTypeId == m_nTypeId);
}
/*
* acquire.
*/
oslInterlockedCount SAL_CALL OStoreLockBytes::acquire (void)
{
return OStoreObject::acquire();
}
/*
* release.
*/
oslInterlockedCount SAL_CALL OStoreLockBytes::release (void)
{
return OStoreObject::release();
}
/*
* create.
*/
storeError OStoreLockBytes::create (
OStorePageManager *pManager,
rtl_uString *pPath,
rtl_uString *pName,
storeAccessMode eMode)
{
rtl::Reference<OStorePageManager> xManager (pManager);
if (!xManager.is())
return store_E_InvalidAccess;
if (!(pPath && pName))
return store_E_InvalidParameter;
osl::MutexGuard aGuard (*xManager);
storeError eErrCode = xManager->getPageSize (m_nPageSize);
if (eErrCode != store_E_None)
return eErrCode;
delete m_pNode;
m_pNode = new(m_nPageSize) inode(m_nPageSize);
if (!m_pNode)
return store_E_OutOfMemory;
rtl::OString aPath (pPath->buffer, pPath->length, RTL_TEXTENCODING_UTF8);
rtl::OString aName (pName->buffer, pName->length, RTL_TEXTENCODING_UTF8);
eErrCode = __store_iget (
*xManager, *m_pNode, STORE_ATTRIB_ISFILE,
aPath.pData, aName.pData, eMode);
if (eErrCode != store_E_None)
return eErrCode;
sal_uInt32 nAttrib = m_pNode->m_aNameBlock.m_nAttrib;
if (!(nAttrib & STORE_ATTRIB_ISFILE))
{
// No ISFILE in older versions (backward compatibility).
if (nAttrib & STORE_ATTRIB_ISLINK)
return store_E_NotFile;
}
// ...
OStorePageDescriptor aDescr (m_pNode->m_aDescr);
if (eMode != store_AccessReadOnly)
eErrCode = xManager->acquirePage (aDescr, store_AccessReadWrite);
else
eErrCode = xManager->acquirePage (aDescr, store_AccessReadOnly);
if (eErrCode != store_E_None)
return eErrCode;
// ...
m_xManager = xManager;
m_bWriteable = (eMode != store_AccessReadOnly);
// Check for truncation.
if (eMode == store_AccessCreate)
{
// Truncate to zero length.
eErrCode = setSize(0);
}
return eErrCode;
}
/*
* readAt.
*/
storeError OStoreLockBytes::readAt (
sal_uInt32 nOffset,
void *pBuffer,
sal_uInt32 nBytes,
sal_uInt32 &rnDone)
{
rnDone = 0;
if (!m_xManager.is())
return store_E_InvalidAccess;
if (!pBuffer)
return store_E_InvalidParameter;
if (!nBytes)
return store_E_None;
// Acquire exclusive access.
osl::MutexGuard aGuard (*m_xManager);
// Determine data length.
OStoreDirectoryPageObject aPage (*m_pNode);
sal_uInt32 nDataLen = aPage.dataLength();
if ((nOffset + nBytes) > nDataLen)
nBytes = nDataLen - nOffset;
// Read data.
sal_uInt8 *pData = (sal_uInt8*)pBuffer;
while ((0 < nBytes) && (nOffset < nDataLen))
{
// Determine 'Offset' scope.
inode::ChunkScope eScope = m_pNode->scope (nOffset);
if (eScope == inode::SCOPE_INTERNAL)
{
// Read from inode page (internal scope).
inode::ChunkDescriptor aDescr (
nOffset, m_pNode->capacity());
sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
nLength = SAL_MIN(nLength, nBytes);
rtl_copyMemory (
&pData[rnDone],
&m_pNode->m_pData[aDescr.m_nOffset],
nLength);
// Adjust counters.
rnDone += nLength;
nOffset += nLength;
nBytes -= nLength;
}
else
{
// Read from data page (external scope).
if (!m_pData)
m_pData = new(m_nPageSize) data(m_nPageSize);
if (!m_pData)
return store_E_OutOfMemory;
OStoreDataPageObject aData (*m_pData);
inode::ChunkDescriptor aDescr (
nOffset - m_pNode->capacity(), m_pData->capacity());
sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
nLength = SAL_MIN(nLength, nBytes);
storeError eErrCode = aPage.get (
aDescr.m_nPage, m_pSingle, m_pDouble, m_pTriple,
aData, *m_xManager, NULL);
if (eErrCode != store_E_None)
{
if (eErrCode != store_E_NotExists)
return eErrCode;
rtl_zeroMemory (
&pData[rnDone],
nLength);
}
else
{
rtl_copyMemory (
&pData[rnDone],
&m_pData->m_pData[aDescr.m_nOffset],
nLength);
}
// Adjust counters.
rnDone += nLength;
nOffset += nLength;
nBytes -= nLength;
}
}
// Done.
return store_E_None;
}
/*
* writeAt.
*/
storeError OStoreLockBytes::writeAt (
sal_uInt32 nOffset,
const void *pBuffer,
sal_uInt32 nBytes,
sal_uInt32 &rnDone)
{
rnDone = 0;
if (!m_xManager.is())
return store_E_InvalidAccess;
if (!m_bWriteable)
return store_E_AccessViolation;
if (!pBuffer)
return store_E_InvalidParameter;
if (!nBytes)
return store_E_None;
// Acquire exclusive access.
osl::MutexGuard aGuard (*m_xManager);
// Write data.
OStoreDirectoryPageObject aPage (*m_pNode);
const sal_uInt8 *pData = (const sal_uInt8*)pBuffer;
storeError eErrCode = store_E_None;
while (nBytes > 0)
{
// Determine 'Offset' scope.
inode::ChunkScope eScope = m_pNode->scope (nOffset);
if (eScope == inode::SCOPE_INTERNAL)
{
// Write to inode page (internal scope).
inode::ChunkDescriptor aDescr (
nOffset, m_pNode->capacity());
sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
nLength = SAL_MIN(nLength, nBytes);
rtl_copyMemory (
&m_pNode->m_pData[aDescr.m_nOffset],
&pData[rnDone], nLength);
// Mark inode dirty.
aPage.touch();
// Adjust counters.
rnDone += nLength;
nOffset += nLength;
nBytes -= nLength;
// Adjust data length.
if (aPage.dataLength() < nOffset)
aPage.dataLength (nOffset);
}
else
{
// Write to data page (external scope).
if (!m_pData)
m_pData = new(m_nPageSize) data(m_nPageSize);
if (!m_pData)
return store_E_OutOfMemory;
OStoreDataPageObject aData (*m_pData);
inode::ChunkDescriptor aDescr (
nOffset - m_pNode->capacity(), m_pData->capacity());
sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
if ((aDescr.m_nOffset > 0) || (nBytes < nLength))
{
// Unaligned. Need to load/create data page.
eErrCode = aPage.get (
aDescr.m_nPage, m_pSingle, m_pDouble, m_pTriple,
aData, *m_xManager, NULL);
if (eErrCode != store_E_None)
{
if (eErrCode != store_E_NotExists)
return eErrCode;
rtl_zeroMemory (
&m_pData->m_pData[0],
m_pData->capacity());
}
}
// Modify data page.
nLength = SAL_MIN(nLength, nBytes);
rtl_copyMemory (
&m_pData->m_pData[aDescr.m_nOffset],
&pData[rnDone], nLength);
// Save data page.
eErrCode = aPage.put (
aDescr.m_nPage, m_pSingle, m_pDouble, m_pTriple,
aData, *m_xManager, NULL);
if (eErrCode != store_E_None)
return eErrCode;
// Adjust counters.
rnDone += nLength;
nOffset += nLength;
nBytes -= nLength;
// Adjust data length.
if (aPage.dataLength() < nOffset)
aPage.dataLength (nOffset);
}
}
// Check for modified inode.
if (aPage.dirty())
return m_xManager->save (aPage);
else
return store_E_None;
}
/*
* flush.
*/
storeError OStoreLockBytes::flush (void)
{
if (!m_xManager.is())
return store_E_InvalidAccess;
return m_xManager->flush();
}
/*
* setSize.
*/
storeError OStoreLockBytes::setSize (sal_uInt32 nSize)
{
if (!m_xManager.is())
return store_E_InvalidAccess;
if (!m_bWriteable)
return store_E_AccessViolation;
// Acquire exclusive access.
osl::MutexGuard aGuard (*m_xManager);
// Determine current length.
OStoreDirectoryPageObject aPage (*m_pNode);
sal_uInt32 nDataLen = aPage.dataLength();
if (nSize == nDataLen)
return store_E_None;
if (nSize < nDataLen)
{
// Truncate.
storeError eErrCode = store_E_None;
// Determine 'Size' scope.
inode::ChunkScope eSizeScope = m_pNode->scope (nSize);
if (eSizeScope == inode::SCOPE_INTERNAL)
{
// Internal 'Size' scope. Determine 'Data' scope.
inode::ChunkScope eDataScope = m_pNode->scope (nDataLen);
if (eDataScope == inode::SCOPE_EXTERNAL)
{
// External 'Data' scope.
if (!m_pData)
m_pData = new(m_nPageSize) data(m_nPageSize);
if (!m_pData)
return store_E_OutOfMemory;
OStoreDataPageObject aData (*m_pData);
// Truncate all external data pages.
eErrCode = aPage.truncate (
0, m_pSingle, m_pDouble, m_pTriple,
aData, *m_xManager, NULL);
if (eErrCode != store_E_None)
return eErrCode;
}
// Truncate internal data page.
inode::ChunkDescriptor aDescr (nSize, m_pNode->capacity());
rtl_zeroMemory (
&m_pNode->m_pData[aDescr.m_nOffset],
aDescr.m_nLength);
}
else
{
// External 'Size' scope.
if (!m_pData)
m_pData = new(m_nPageSize) data(m_nPageSize);
if (!m_pData)
return store_E_OutOfMemory;
OStoreDataPageObject aData (*m_pData);
// Truncate external data pages.
inode::ChunkDescriptor aDescr (
nSize - m_pNode->capacity(), m_pData->capacity());
sal_uInt32 nPage = aDescr.m_nPage;
if (aDescr.m_nOffset) nPage += 1;
eErrCode = aPage.truncate (
nPage, m_pSingle, m_pDouble, m_pTriple,
aData, *m_xManager, NULL);
if (eErrCode != store_E_None)
return eErrCode;
}
}
// Set (extended or truncated) size.
aPage.dataLength (nSize);
// Save modified inode.
return m_xManager->save (aPage);
}
/*
* stat.
*/
storeError OStoreLockBytes::stat (sal_uInt32 &rnSize)
{
rnSize = 0;
if (!m_xManager.is())
return store_E_InvalidAccess;
rnSize = m_pNode->m_aDataBlock.m_nDataLen;
return store_E_None;
}
/*
* lockRange.
*/
storeError OStoreLockBytes::lockRange (
sal_uInt32 nOffset, sal_uInt32 nBytes)
{
// (NYI).
return store_E_None;
}
/*
* unlockRange.
*/
storeError OStoreLockBytes::unlockRange (
sal_uInt32 nOffset, sal_uInt32 nBytes)
{
// (NYI).
return store_E_None;
}