| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_store.hxx" |
| |
| #include "storlckb.hxx" |
| |
| #include "sal/types.h" |
| #include "sal/macros.h" |
| #include "rtl/string.h" |
| #include "rtl/ref.hxx" |
| #include "osl/mutex.hxx" |
| |
| #include "store/types.h" |
| #include "object.hxx" |
| |
| #include "storbase.hxx" |
| #include "stordata.hxx" |
| #include "storpage.hxx" |
| |
| using namespace store; |
| |
| /*======================================================================== |
| * |
| * OStoreLockBytes implementation. |
| * |
| *======================================================================*/ |
| const sal_uInt32 OStoreLockBytes::m_nTypeId = sal_uInt32(0x94190310); |
| |
| /* |
| * OStoreLockBytes. |
| */ |
| OStoreLockBytes::OStoreLockBytes (void) |
| : m_xManager (), |
| m_xNode (), |
| m_bWriteable (false) |
| { |
| } |
| |
| /* |
| * ~OStoreLockBytes. |
| */ |
| OStoreLockBytes::~OStoreLockBytes (void) |
| { |
| if (m_xManager.is()) |
| { |
| if (m_xNode.is()) |
| { |
| OStorePageDescriptor aDescr (m_xNode->m_aDescr); |
| if (m_bWriteable) |
| m_xManager->releasePage (aDescr, store_AccessReadWrite); |
| else |
| m_xManager->releasePage (aDescr, store_AccessReadOnly); |
| } |
| } |
| } |
| |
| /* |
| * isKindOf. |
| */ |
| sal_Bool SAL_CALL OStoreLockBytes::isKindOf (sal_uInt32 nTypeId) |
| { |
| return (nTypeId == m_nTypeId); |
| } |
| |
| /* |
| * create. |
| */ |
| storeError OStoreLockBytes::create ( |
| OStorePageManager *pManager, |
| rtl_String *pPath, |
| rtl_String *pName, |
| storeAccessMode eMode) |
| { |
| rtl::Reference<OStorePageManager> xManager (pManager); |
| if (!xManager.is()) |
| return store_E_InvalidAccess; |
| |
| if (!(pPath && pName)) |
| return store_E_InvalidParameter; |
| |
| OStoreDirectoryPageObject aPage; |
| storeError eErrCode = xManager->iget ( |
| aPage, STORE_ATTRIB_ISFILE, |
| pPath, pName, eMode); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| |
| if (!(aPage.attrib() & STORE_ATTRIB_ISFILE)) |
| { |
| // No ISFILE in older versions (backward compatibility). |
| if (aPage.attrib() & STORE_ATTRIB_ISLINK) |
| return store_E_NotFile; |
| } |
| |
| // ... |
| inode_holder_type xNode (aPage.get()); |
| if (eMode != store_AccessReadOnly) |
| eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadWrite); |
| else |
| eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| |
| // ... |
| m_xManager = xManager; |
| m_xNode = xNode; |
| 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_xNode.get()); |
| |
| sal_uInt32 nDataLen = aPage.dataLength(); |
| if ((nOffset + nBytes) > nDataLen) |
| nBytes = nDataLen - nOffset; |
| |
| // Read data. |
| OStoreDataPageObject aData; |
| sal_uInt8 *pData = (sal_uInt8*)pBuffer; |
| while ((0 < nBytes) && (nOffset < nDataLen)) |
| { |
| // Determine 'Offset' scope. |
| inode::ChunkScope eScope = m_xNode->scope (nOffset); |
| if (eScope == inode::SCOPE_INTERNAL) |
| { |
| // Read from inode page (internal scope). |
| inode::ChunkDescriptor aDescr ( |
| nOffset, m_xNode->capacity()); |
| |
| sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); |
| nLength = SAL_MIN(nLength, nBytes); |
| |
| memcpy ( |
| &pData[rnDone], |
| &m_xNode->m_pData[aDescr.m_nOffset], |
| nLength); |
| |
| // Adjust counters. |
| rnDone += nLength; |
| nOffset += nLength; |
| nBytes -= nLength; |
| } |
| else |
| { |
| // Read from data page (external scope). |
| inode::ChunkDescriptor aDescr ( |
| nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ |
| |
| sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); |
| nLength = SAL_MIN(nLength, nBytes); |
| |
| storeError eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager); |
| if (eErrCode != store_E_None) |
| { |
| if (eErrCode != store_E_NotExists) |
| return eErrCode; |
| |
| memset ( |
| &pData[rnDone], |
| 0, |
| nLength); |
| } |
| else |
| { |
| PageHolderObject< data > xData (aData.makeHolder<data>()); |
| memcpy ( |
| &pData[rnDone], |
| &xData->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_xNode.get()); |
| const sal_uInt8 *pData = (const sal_uInt8*)pBuffer; |
| |
| storeError eErrCode = store_E_None; |
| while (nBytes > 0) |
| { |
| // Determine 'Offset' scope. |
| inode::ChunkScope eScope = m_xNode->scope (nOffset); |
| if (eScope == inode::SCOPE_INTERNAL) |
| { |
| // Write to inode page (internal scope). |
| inode::ChunkDescriptor aDescr ( |
| nOffset, m_xNode->capacity()); |
| |
| sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); |
| nLength = SAL_MIN(nLength, nBytes); |
| |
| memcpy ( |
| &m_xNode->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). |
| OStoreDataPageObject aData; |
| |
| inode::ChunkDescriptor aDescr ( |
| nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ |
| |
| sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength); |
| if ((aDescr.m_nOffset > 0) || (nBytes < nLength)) |
| { |
| // Unaligned. Need to load/create data page. |
| // @@@ loadOrCreate() |
| eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager); |
| if (eErrCode != store_E_None) |
| { |
| if (eErrCode != store_E_NotExists) |
| return eErrCode; |
| |
| eErrCode = aData.construct<data>(m_xManager->allocator()); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| } |
| } |
| |
| PageHolderObject< data > xData (aData.makeHolder<data>()); |
| if (!xData.is()) |
| { |
| eErrCode = aData.construct<data>(m_xManager->allocator()); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| xData = aData.makeHolder<data>(); |
| } |
| |
| // Modify data page. |
| nLength = SAL_MIN(nLength, nBytes); |
| memcpy ( |
| &xData->m_pData[aDescr.m_nOffset], |
| &pData[rnDone], nLength); |
| |
| // Save data page. |
| eErrCode = aPage.write (aDescr.m_nPage, aData, *m_xManager); |
| 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->saveObjectAt (aPage, aPage.location()); |
| 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_xNode.get()); |
| 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_xNode->scope (nSize); |
| if (eSizeScope == inode::SCOPE_INTERNAL) |
| { |
| // Internal 'Size' scope. Determine 'Data' scope. |
| inode::ChunkScope eDataScope = m_xNode->scope (nDataLen); |
| if (eDataScope == inode::SCOPE_EXTERNAL) |
| { |
| // External 'Data' scope. Truncate all external data pages. |
| eErrCode = aPage.truncate (0, *m_xManager); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| } |
| |
| // Truncate internal data page. |
| inode::ChunkDescriptor aDescr (nSize, m_xNode->capacity()); |
| memset ( |
| &(m_xNode->m_pData[aDescr.m_nOffset]), |
| 0, aDescr.m_nLength); |
| } |
| else |
| { |
| // External 'Size' scope. Truncate external data pages. |
| inode::ChunkDescriptor aDescr ( |
| nSize - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@ |
| |
| sal_uInt32 nPage = aDescr.m_nPage; |
| if (aDescr.m_nOffset) nPage += 1; |
| |
| eErrCode = aPage.truncate (nPage, *m_xManager); |
| if (eErrCode != store_E_None) |
| return eErrCode; |
| } |
| } |
| |
| // Set (extended or truncated) size. |
| aPage.dataLength (nSize); |
| |
| // Save modified inode. |
| return m_xManager->saveObjectAt (aPage, aPage.location()); |
| } |
| |
| /* |
| * stat. |
| */ |
| storeError OStoreLockBytes::stat (sal_uInt32 &rnSize) |
| { |
| rnSize = 0; |
| |
| if (!m_xManager.is()) |
| return store_E_InvalidAccess; |
| |
| OStoreDirectoryPageObject aPage (m_xNode.get()); |
| rnSize = aPage.dataLength(); |
| return store_E_None; |
| } |