/* -*- 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 "storlckb.hxx" #include #include #include #include #include #include "storbase.hxx" #include "stordata.hxx" #include "storpage.hxx" using namespace store; /*======================================================================== * * OStoreLockBytes implementation. * *======================================================================*/ const sal_uInt32 OStoreLockBytes::m_nTypeId(0x94190310); /* * OStoreLockBytes. */ OStoreLockBytes::OStoreLockBytes() : m_xManager (), m_xNode (), m_bWriteable (false) { } /* * ~OStoreLockBytes. */ OStoreLockBytes::~OStoreLockBytes() { if (m_xManager.is() && m_xNode.is()) { m_xManager->releasePage(m_xNode->m_aDescr); } } /* * isKindOf. */ bool OStoreLockBytes::isKindOf (sal_uInt32 nTypeId) { return (nTypeId == m_nTypeId); } /* * create. */ storeError OStoreLockBytes::create ( OStorePageManager *pManager, rtl_String const *pPath, rtl_String const *pName, storeAccessMode eMode) { rtl::Reference 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 != storeAccessMode::ReadOnly) eErrCode = xManager->acquirePage (xNode->m_aDescr, storeAccessMode::ReadWrite); else eErrCode = xManager->acquirePage (xNode->m_aDescr, storeAccessMode::ReadOnly); if (eErrCode != store_E_None) return eErrCode; m_xManager = xManager; m_xNode = xNode; m_bWriteable = (eMode != storeAccessMode::ReadOnly); // Check for truncation. if (eMode == storeAccessMode::Create) { // 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 = static_cast(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); if(nLength > nBytes) { 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); if(nLength > nBytes) { 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()); 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 = static_cast(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); if(nLength > nBytes) { 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(m_xManager->allocator()); if (eErrCode != store_E_None) return eErrCode; } } PageHolderObject< data > xData (aData.makeHolder()); if (!xData.is()) { eErrCode = aData.construct(m_xManager->allocator()); if (eErrCode != store_E_None) return eErrCode; xData = aData.makeHolder(); } // Modify data page. if(nLength > nBytes) { 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; } /* * 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()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */