/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: storlckb.cxx,v $ * * $Revision: 1.8 $ * * last change: $Author: obo $ $Date: 2006-09-17 01:12:50 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 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 * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_store.hxx" #define _STORE_STORLCKB_CXX_ "$Revision: 1.8 $" #ifndef _SAL_TYPES_H_ #include #endif #ifndef _SAL_MACROS_H_ #include #endif #ifndef _RTL_MEMORY_H_ #include #endif #ifndef _RTL_TEXTCVT_H_ #include #endif #ifndef _RTL_STRING_HXX_ #include #endif #ifndef _RTL_REF_HXX_ #include #endif #ifndef _OSL_MUTEX_HXX_ #include #endif #ifndef _STORE_TYPES_H_ #include #endif #ifndef _STORE_OBJECT_HXX_ #include #endif #ifndef _STORE_LOCKBYTE_HXX_ #include #endif #ifndef _STORE_STORBASE_HXX_ #include #endif #ifndef _STORE_STORDATA_HXX_ #include #endif #ifndef _STORE_STORPAGE_HXX_ #include #endif #ifndef _STORE_STORLCKB_HXX_ #include #endif using namespace store; /*======================================================================== * * OStore... internals. * *======================================================================*/ /* * __store_convertTextToUnicode. */ inline sal_Size __store_convertTextToUnicode ( rtl_TextToUnicodeConverter hConverter, const sal_Char *pSrcBuffer, sal_Size nSrcLength, sal_Unicode *pDstBuffer, sal_Size nDstLength) { sal_uInt32 nCvtInfo = 0; sal_Size 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); } } 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 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_Size n = rtl_str_getLength (p); sal_Size 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_pNode (NULL), m_pData (NULL), m_pSingle (NULL), m_pDouble (NULL), m_pTriple (NULL), m_nPageSize (0), 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); m_xManager->releasePage (aDescr); } } 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 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, sal_uInt32) { // (NYI). return store_E_None; } /* * unlockRange. */ storeError OStoreLockBytes::unlockRange (sal_uInt32, sal_uInt32) { // (NYI). return store_E_None; }