LCOV - code coverage report
Current view: top level - store/source - storpage.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 140 400 35.0 %
Date: 2015-06-13 12:38:46 Functions: 13 25 52.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "storpage.hxx"
      21             : 
      22             : #include "sal/types.h"
      23             : #include "sal/log.hxx"
      24             : #include "rtl/string.h"
      25             : #include "rtl/ref.hxx"
      26             : #include "osl/diagnose.h"
      27             : #include "osl/mutex.hxx"
      28             : 
      29             : #include "store/types.h"
      30             : 
      31             : #include "object.hxx"
      32             : #include "lockbyte.hxx"
      33             : 
      34             : #include "storbase.hxx"
      35             : #include "stordata.hxx"
      36             : #include "stortree.hxx"
      37             : 
      38             : using namespace store;
      39             : 
      40             : /*========================================================================
      41             :  *
      42             :  * OStorePageManager implementation.
      43             :  *
      44             :  *======================================================================*/
      45             : const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
      46             : 
      47             : /*
      48             :  * OStorePageManager.
      49             :  */
      50         150 : OStorePageManager::OStorePageManager()
      51             : {
      52         150 : }
      53             : 
      54             : /*
      55             :  * ~OStorePageManager.
      56             :  */
      57         444 : OStorePageManager::~OStorePageManager()
      58             : {
      59         444 : }
      60             : 
      61             : /*
      62             :  * isKindOf.
      63             :  */
      64        1487 : bool OStorePageManager::isKindOf (sal_uInt32 nTypeId)
      65             : {
      66        1487 :     return (nTypeId == m_nTypeId);
      67             : }
      68             : 
      69             : /*
      70             :  * initialize (two-phase construction).
      71             :  * Precond: none.
      72             :  */
      73         150 : storeError OStorePageManager::initialize (
      74             :     ILockBytes *    pLockBytes,
      75             :     storeAccessMode eAccessMode,
      76             :     sal_uInt16 &    rnPageSize)
      77             : {
      78             :     // Acquire exclusive access.
      79         150 :     osl::MutexGuard aGuard(*this);
      80             : 
      81             :     // Check arguments.
      82         150 :     if (!pLockBytes)
      83           0 :         return store_E_InvalidParameter;
      84             : 
      85             :     // Initialize base.
      86         150 :     storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
      87         150 :     if (eErrCode != store_E_None)
      88           2 :         return eErrCode;
      89             : 
      90             :     // Check for (not) writeable.
      91         148 :     if (!base::isWriteable())
      92             :     {
      93             :         // Readonly. Load RootNode.
      94           0 :         return base::loadObjectAt (m_aRoot, rnPageSize);
      95             :     }
      96             : 
      97             :     // Writeable. Load or Create RootNode.
      98         148 :     eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
      99         148 :     if (eErrCode == store_E_Pending)
     100             :     {
     101             :         // Creation notification.
     102         148 :         PageHolderObject< page > xRoot (m_aRoot.get());
     103             : 
     104             :         // Pre-allocate left most entry (ugly, but we can't insert to left).
     105         148 :         OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
     106         148 :         xRoot->insert (0, entry(aKey));
     107             : 
     108             :         // Save RootNode.
     109         148 :         eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
     110             :     }
     111             : 
     112             :     // Done.
     113         148 :     return eErrCode;
     114             : }
     115             : 
     116             : /*
     117             :  * find_lookup (w/o split()).
     118             :  * Internal: Precond: initialized, readable, exclusive access.
     119             :  */
     120        1339 : storeError OStorePageManager::find_lookup (
     121             :     OStoreBTreeNodeObject & rNode,
     122             :     sal_uInt16 &            rIndex,
     123             :     OStorePageKey const &   rKey)
     124             : {
     125             :     // Find Node and Index.
     126        1339 :     storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
     127        1339 :     if (eErrCode != store_E_None)
     128           0 :         return eErrCode;
     129             : 
     130             :     // Greater or Equal.
     131        1339 :     PageHolderObject< page > xPage (rNode.get());
     132             :     SAL_WARN_IF(rIndex >= xPage->usageCount(), "store", "store::PageManager::find_lookup(): logic error");
     133        1339 :     entry e (xPage->m_pData[rIndex]);
     134             : 
     135             :     // Check for exact match.
     136        1339 :     if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
     137             :     {
     138             :         // Page not present.
     139         825 :         return store_E_NotExists;
     140             :     }
     141             : 
     142             :     // Check address.
     143         514 :     if (e.m_aLink.location() == STORE_PAGE_NULL)
     144             :     {
     145             :         // Page not present.
     146         148 :         return store_E_NotExists;
     147             :     }
     148             : 
     149         366 :     return store_E_None;
     150             : }
     151             : 
     152             : /*
     153             :  * remove_Impl (possibly down from root).
     154             :  * Internal: Precond: initialized, writeable, exclusive access.
     155             :  */
     156             : 
     157           9 : storeError OStorePageManager::remove_Impl (entry & rEntry)
     158             : {
     159           9 :     OStoreBTreeNodeObject aNode (m_aRoot.get());
     160             : 
     161             :     // Check current page index.
     162          18 :     PageHolderObject< page > xPage (aNode.get());
     163           9 :     sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
     164           9 :     if (!(i < n))
     165             :     {
     166             :         // Path to entry not exists (Must not happen(?)).
     167           0 :         return store_E_NotExists;
     168             :     }
     169             : 
     170             :     // Compare entry.
     171           9 :     entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
     172             : 
     173             :     // Iterate down until equal match.
     174           9 :     while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
     175             :     {
     176             :         // Check link address.
     177           0 :         sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
     178           0 :         if (nAddr == STORE_PAGE_NULL)
     179             :         {
     180             :             // Path to entry not exists (Must not happen(?)).
     181           0 :             return store_E_NotExists;
     182             :         }
     183             : 
     184             :         // Load link page.
     185           0 :         storeError eErrCode = loadObjectAt (aNode, nAddr);
     186           0 :         if (eErrCode != store_E_None)
     187           0 :             return eErrCode;
     188             : 
     189           0 :         PageHolderObject< page > xNext (aNode.get());
     190           0 :         xNext.swap (xPage);
     191             : 
     192             :         // Check index.
     193           0 :         i = xPage->find (rEntry), n = xPage->usageCount();
     194           0 :         if (!(i < n))
     195             :         {
     196             :             // Path to entry not exists (Must not happen(?)).
     197           0 :             return store_E_NotExists;
     198             :         }
     199             : 
     200             :         // Compare entry.
     201           0 :         result = rEntry.compare (xPage->m_pData[i]);
     202           0 :     }
     203             : 
     204             :     SAL_WARN_IF(
     205             :         result == entry::COMPARE_LESS,
     206             :         "store",
     207             :         "OStorePageManager::remove(): find failed");
     208             : 
     209             :     // Check entry comparison.
     210           9 :     if (result == entry::COMPARE_LESS)
     211             :     {
     212             :         // Must not happen.
     213           0 :         return store_E_Unknown;
     214             :     }
     215             : 
     216             :     // Remove down from current page (recursive).
     217          18 :     return aNode.remove (i, rEntry, *this);
     218             : }
     219             : 
     220             : /*
     221             :  * namei.
     222             :  * Precond: none (static).
     223             :  */
     224        1339 : storeError OStorePageManager::namei (
     225             :     const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
     226             : {
     227             :     // Check parameter.
     228        1339 :     if (!(pPath && pName))
     229           0 :         return store_E_InvalidParameter;
     230             : 
     231             :     // Check name length.
     232        1339 :     if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
     233           0 :         return store_E_NameTooLong;
     234             : 
     235             :     // Transform pathname into key.
     236        1339 :     rKey.m_nLow  = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
     237        1339 :     rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
     238             : 
     239             :     // Done.
     240        1339 :     return store_E_None;
     241             : }
     242             : 
     243             : /*
     244             :  * iget.
     245             :  * Precond: initialized.
     246             :  */
     247        1330 : storeError OStorePageManager::iget (
     248             :     OStoreDirectoryPageObject & rPage,
     249             :     sal_uInt32                  nAttrib,
     250             :     const rtl_String          * pPath,
     251             :     const rtl_String          * pName,
     252             :     storeAccessMode             eMode)
     253             : {
     254             :     // Acquire exclusive access.
     255        1330 :     osl::MutexGuard aGuard(*this);
     256             : 
     257             :     // Check precond.
     258        1330 :     if (!self::isValid())
     259           0 :         return store_E_InvalidAccess;
     260             : 
     261             :     // Setup inode page key.
     262        1330 :     OStorePageKey aKey;
     263        1330 :     storeError eErrCode = namei (pPath, pName, aKey);
     264        1330 :     if (eErrCode != store_E_None)
     265           0 :         return eErrCode;
     266             : 
     267             :     // Check for directory.
     268        1330 :     if (nAttrib & STORE_ATTRIB_ISDIR)
     269             :     {
     270             :         // Ugly, but necessary (backward compatibility).
     271         915 :         aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
     272             :     }
     273             : 
     274             :     // Load inode page.
     275        1330 :     eErrCode = load_dirpage_Impl (aKey, rPage);
     276        1330 :     if (eErrCode != store_E_None)
     277             :     {
     278             :         // Check mode and reason.
     279         973 :         if (eErrCode != store_E_NotExists)
     280          14 :             return eErrCode;
     281             : 
     282         973 :         if (eMode == store_AccessReadWrite)
     283          14 :             return store_E_NotExists;
     284         959 :         if (eMode == store_AccessReadOnly)
     285           0 :             return store_E_NotExists;
     286             : 
     287         959 :         if (!base::isWriteable())
     288           0 :             return store_E_AccessViolation;
     289             : 
     290             :         // Create inode page.
     291         959 :         eErrCode = rPage.construct< inode >(base::allocator());
     292         959 :         if (eErrCode != store_E_None)
     293           0 :             return eErrCode;
     294             : 
     295             :         // Setup inode nameblock.
     296         959 :         PageHolderObject< inode > xPage (rPage.get());
     297             : 
     298         959 :         rPage.key (aKey);
     299         959 :         rPage.attrib (nAttrib);
     300             : 
     301             :         memcpy (
     302         959 :             &(xPage->m_aNameBlock.m_pData[0]),
     303        1918 :             pName->buffer, pName->length);
     304             : 
     305             :         // Save inode page.
     306         959 :         eErrCode = save_dirpage_Impl (aKey, rPage);
     307         959 :         if (eErrCode != store_E_None)
     308           0 :             return eErrCode;
     309             :     }
     310             : 
     311             :     // Check for symbolic link.
     312        1316 :     if (rPage.attrib() & STORE_ATTRIB_ISLINK)
     313             :     {
     314             :         // Obtain 'Destination' page key.
     315           0 :         PageHolderObject< inode > xPage (rPage.get());
     316           0 :         OStorePageKey aDstKey;
     317           0 :         memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
     318             : 
     319             :         // Load 'Destination' inode.
     320           0 :         eErrCode = load_dirpage_Impl (aDstKey, rPage);
     321           0 :         if (eErrCode != store_E_None)
     322           0 :             return eErrCode;
     323             :     }
     324             : 
     325             :     // Done.
     326        1316 :     return store_E_None;
     327             : }
     328             : 
     329             : /*
     330             :  * iterate.
     331             :  * Precond: initialized.
     332             :  * ToDo: skip hardlink entries.
     333             :  */
     334          78 : storeError OStorePageManager::iterate (
     335             :     OStorePageKey &  rKey,
     336             :     OStorePageLink & rLink,
     337             :     sal_uInt32 &     rAttrib)
     338             : {
     339             :     // Acquire exclusive access.
     340          78 :     osl::MutexGuard aGuard(*this);
     341             : 
     342             :     // Check precond.
     343          78 :     if (!self::isValid())
     344           0 :         return store_E_InvalidAccess;
     345             : 
     346             :     // Find NodePage and Index.
     347         156 :     OStoreBTreeNodeObject aNode;
     348          78 :     sal_uInt16 i = 0;
     349          78 :     storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
     350          78 :     if (eErrCode != store_E_None)
     351           0 :         return eErrCode;
     352             : 
     353             :     // GreaterEqual. Found next entry.
     354         156 :     PageHolderObject< page > xNode (aNode.get());
     355          78 :     entry e (xNode->m_pData[i]);
     356             : 
     357             :     // Setup result.
     358          78 :     rKey    = e.m_aKey;
     359          78 :     rLink   = e.m_aLink;
     360          78 :     rAttrib = store::ntohl(e.m_nAttrib);
     361             : 
     362             :     // Done.
     363         156 :     return store_E_None;
     364             : }
     365             : 
     366             : /*
     367             :  * load => private: iget() @@@
     368             :  * Internal: Precond: initialized, exclusive access.
     369             :  */
     370        1330 : storeError OStorePageManager::load_dirpage_Impl (
     371             :     const OStorePageKey       &rKey,
     372             :     OStoreDirectoryPageObject &rPage)
     373             : {
     374             :     // Find Node and Index.
     375        1330 :     OStoreBTreeNodeObject aNode;
     376        1330 :     sal_uInt16 i = 0;
     377        1330 :     storeError eErrCode = find_lookup (aNode, i, rKey);
     378        1330 :     if (eErrCode != store_E_None)
     379         973 :         return eErrCode;
     380             : 
     381             :     // Existing entry. Load page.
     382         714 :     PageHolderObject< page > xNode (aNode.get());
     383         357 :     entry e (xNode->m_pData[i]);
     384        1687 :     return loadObjectAt (rPage, e.m_aLink.location());
     385             : }
     386             : 
     387             : /*
     388             :  * save => private: iget(), rebuild() @@@
     389             :  * Internal: Precond: initialized, writeable, exclusive access.
     390             :  */
     391         959 : storeError OStorePageManager::save_dirpage_Impl (
     392             :     const OStorePageKey       &rKey,
     393             :     OStoreDirectoryPageObject &rPage)
     394             : {
     395             :     // Find NodePage and Index.
     396         959 :     node aNode;
     397         959 :     sal_uInt16 i = 0;
     398             : 
     399         959 :     storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
     400        1918 :     PageHolderObject< page > xNode (aNode.get());
     401         959 :     if (eErrCode != store_E_None)
     402             :     {
     403         148 :         if (eErrCode != store_E_AlreadyExists)
     404           0 :             return eErrCode;
     405             : 
     406             :         // Existing entry.
     407         148 :         entry e (xNode->m_pData[i]);
     408         148 :         if (e.m_aLink.location() != STORE_PAGE_NULL)
     409             :         {
     410             :             // Save page to existing location.
     411           0 :             return saveObjectAt (rPage, e.m_aLink.location());
     412             :         }
     413             : 
     414             :         // Allocate page.
     415         148 :         eErrCode = base::allocate (rPage);
     416         148 :         if (eErrCode != store_E_None)
     417           0 :             return eErrCode;
     418             : 
     419             :         // Update page location.
     420         148 :         xNode->m_pData[i].m_aLink = rPage.location();
     421             : 
     422             :         // Save modified NodePage.
     423         148 :         return saveObjectAt (aNode, aNode.location());
     424             :     }
     425             : 
     426             :     // Allocate page.
     427         811 :     eErrCode = base::allocate (rPage);
     428         811 :     if (eErrCode != store_E_None)
     429           0 :         return eErrCode;
     430             : 
     431             :     // Insert.
     432         811 :     OStorePageLink aLink (rPage.location());
     433         811 :     xNode->insert (i + 1, entry (rKey, aLink));
     434             : 
     435             :     // Save modified NodePage.
     436        1770 :     return saveObjectAt (aNode, aNode.location());
     437             : }
     438             : 
     439             : /*
     440             :  * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)].
     441             :  * Precond: initialized.
     442             :  */
     443           0 : storeError OStorePageManager::attrib (
     444             :     const OStorePageKey &rKey,
     445             :     sal_uInt32           nMask1,
     446             :     sal_uInt32           nMask2,
     447             :     sal_uInt32          &rAttrib)
     448             : {
     449             :     // Acquire exclusive access.
     450           0 :     osl::MutexGuard aGuard(*this);
     451             : 
     452             :     // Check precond.
     453           0 :     if (!self::isValid())
     454           0 :         return store_E_InvalidAccess;
     455             : 
     456             :     // Find NodePage and index.
     457           0 :     OStoreBTreeNodeObject aNode;
     458           0 :     sal_uInt16 i = 0;
     459           0 :     storeError eErrCode = find_lookup (aNode, i, rKey);
     460           0 :     if (eErrCode != store_E_None)
     461           0 :         return eErrCode;
     462             : 
     463             :     // Existing entry.
     464           0 :     PageHolderObject< page > xNode (aNode.get());
     465           0 :     entry e (xNode->m_pData[i]);
     466           0 :     if (nMask1 != nMask2)
     467             :     {
     468             :         // Evaluate new attributes.
     469           0 :         sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib);
     470             : 
     471           0 :         nAttrib &= ~nMask1;
     472           0 :         nAttrib |=  nMask2;
     473             : 
     474           0 :         if (store::htonl(nAttrib) != e.m_nAttrib)
     475             :         {
     476             :             // Check access mode.
     477           0 :             if (base::isWriteable())
     478             :             {
     479             :                 // Set new attributes.
     480           0 :                 e.m_nAttrib = store::htonl(nAttrib);
     481           0 :                 xNode->m_pData[i] = e;
     482             : 
     483             :                 // Save modified NodePage.
     484           0 :                 eErrCode = saveObjectAt (aNode, aNode.location());
     485             :             }
     486             :             else
     487             :             {
     488             :                 // Access denied.
     489           0 :                 eErrCode = store_E_AccessViolation;
     490             :             }
     491             :         }
     492             :     }
     493             : 
     494             :     // Obtain current attributes.
     495           0 :     rAttrib = store::ntohl(e.m_nAttrib);
     496           0 :     return eErrCode;
     497             : }
     498             : 
     499             : /*
     500             :  * link (insert 'Source' as hardlink to 'Destination').
     501             :  * Precond: initialized, writeable.
     502             :  */
     503           0 : storeError OStorePageManager::link (
     504             :     const OStorePageKey &rSrcKey,
     505             :     const OStorePageKey &rDstKey)
     506             : {
     507             :     // Acquire exclusive access.
     508           0 :     osl::MutexGuard aGuard(*this);
     509             : 
     510             :     // Check precond.
     511           0 :     if (!self::isValid())
     512           0 :         return store_E_InvalidAccess;
     513             : 
     514           0 :     if (!base::isWriteable())
     515           0 :         return store_E_AccessViolation;
     516             : 
     517             :     // Find 'Destination' NodePage and Index.
     518           0 :     OStoreBTreeNodeObject aDstNode;
     519           0 :     sal_uInt16 i = 0;
     520           0 :     storeError eErrCode = find_lookup (aDstNode, i, rDstKey);
     521           0 :     if (eErrCode != store_E_None)
     522           0 :         return eErrCode;
     523             : 
     524             :     // Existing 'Destination' entry.
     525           0 :     PageHolderObject< page > xDstNode (aDstNode.get());
     526           0 :     entry e (xDstNode->m_pData[i]);
     527           0 :     OStorePageLink aDstLink (e.m_aLink);
     528             : 
     529             :     // Find 'Source' NodePage and Index.
     530           0 :     OStoreBTreeNodeObject aSrcNode;
     531           0 :     eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this);
     532           0 :     if (eErrCode != store_E_None)
     533           0 :         return eErrCode;
     534             : 
     535             :     // Insert 'Source' entry.
     536           0 :     PageHolderObject< page > xSrcNode (aSrcNode.get());
     537           0 :     xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK));
     538           0 :     return saveObjectAt (aSrcNode, aSrcNode.location());
     539             : }
     540             : 
     541             : /*
     542             :  * symlink (insert 'Source' DirectoryPage as symlink to 'Destination').
     543             :  * Precond: initialized, writeable.
     544             :  */
     545           0 : storeError OStorePageManager::symlink (
     546             :     const rtl_String    *pSrcPath,
     547             :     const rtl_String    *pSrcName,
     548             :     const OStorePageKey &rDstKey)
     549             : {
     550             :     // Acquire exclusive access.
     551           0 :     osl::MutexGuard aGuard(*this);
     552             : 
     553             :     // Check precond.
     554           0 :     if (!self::isValid())
     555           0 :         return store_E_InvalidAccess;
     556             : 
     557           0 :     if (!base::isWriteable())
     558           0 :         return store_E_AccessViolation;
     559             : 
     560             :     // Check 'Source' parameter.
     561           0 :     storeError eErrCode = store_E_InvalidParameter;
     562           0 :     if (!(pSrcPath && pSrcName))
     563           0 :         return eErrCode;
     564             : 
     565             :     // Setup 'Source' page key.
     566           0 :     OStorePageKey aSrcKey;
     567           0 :     eErrCode = namei (pSrcPath, pSrcName, aSrcKey);
     568           0 :     if (eErrCode != store_E_None)
     569           0 :         return eErrCode;
     570             : 
     571             :     // Find 'Source' NodePage and Index.
     572           0 :     OStoreBTreeNodeObject aSrcNode;
     573           0 :     sal_uInt16 i = 0;
     574           0 :     eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this);
     575           0 :     if (eErrCode != store_E_None)
     576           0 :         return eErrCode;
     577             : 
     578             :     // Initialize directory page.
     579           0 :     OStoreDirectoryPageObject aPage;
     580           0 :     eErrCode = aPage.construct< inode >(base::allocator());
     581           0 :     if (eErrCode != store_E_None)
     582           0 :         return eErrCode;
     583             : 
     584             :     // Setup as 'Source' directory page.
     585           0 :     inode_holder_type xNode (aPage.get());
     586           0 :     aPage.key (aSrcKey);
     587             :     memcpy (
     588           0 :         &(xNode->m_aNameBlock.m_pData[0]),
     589           0 :         pSrcName->buffer, pSrcName->length);
     590             : 
     591             :     // Store 'Destination' page key.
     592           0 :     OStorePageKey aDstKey (rDstKey);
     593           0 :     memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey));
     594             : 
     595             :     // Mark 'Source' as symbolic link to 'Destination'.
     596           0 :     aPage.attrib (STORE_ATTRIB_ISLINK);
     597           0 :     aPage.dataLength (sal_uInt32(sizeof(aDstKey)));
     598             : 
     599             :     // Allocate and save 'Source' directory page.
     600           0 :     eErrCode = base::allocate (aPage);
     601           0 :     if (eErrCode != store_E_None)
     602           0 :         return eErrCode;
     603             : 
     604             :     // Insert 'Source' entry.
     605           0 :     PageHolderObject< page > xSrcNode (aSrcNode.get());
     606           0 :     OStorePageLink aSrcLink (aPage.location());
     607           0 :     xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink));
     608             : 
     609             :     // Save modified NodePage.
     610           0 :     return saveObjectAt (aSrcNode, aSrcNode.location());
     611             : }
     612             : 
     613             : /*
     614             :  * rename.
     615             :  * Precond: initialized, writeable.
     616             :  */
     617           0 : storeError OStorePageManager::rename (
     618             :     const OStorePageKey &rSrcKey,
     619             :     const rtl_String    *pDstPath,
     620             :     const rtl_String    *pDstName)
     621             : {
     622             :     // Acquire exclusive access.
     623           0 :     osl::MutexGuard aGuard(*this);
     624             : 
     625             :     // Check precond.
     626           0 :     if (!self::isValid())
     627           0 :         return store_E_InvalidAccess;
     628             : 
     629           0 :     if (!base::isWriteable())
     630           0 :         return store_E_AccessViolation;
     631             : 
     632             :     // Check 'Destination' parameter.
     633           0 :     storeError eErrCode = store_E_InvalidParameter;
     634           0 :     if (!(pDstPath && pDstName))
     635           0 :         return eErrCode;
     636             : 
     637             :     // Setup 'Destination' page key.
     638           0 :     OStorePageKey aDstKey;
     639           0 :     eErrCode = namei (pDstPath, pDstName, aDstKey);
     640           0 :     if (eErrCode != store_E_None)
     641           0 :         return eErrCode;
     642             : 
     643             :     // Find 'Source' NodePage and Index.
     644           0 :     OStoreBTreeNodeObject aSrcNode;
     645           0 :     sal_uInt16 i = 0;
     646           0 :     eErrCode = find_lookup (aSrcNode, i, rSrcKey);
     647           0 :     if (eErrCode != store_E_None)
     648           0 :         return eErrCode;
     649             : 
     650             :     // Existing 'Source' entry.
     651           0 :     PageHolderObject< page > xSrcNode (aSrcNode.get());
     652           0 :     entry e (xSrcNode->m_pData[i]);
     653             : 
     654             :     // Check for (not a) hardlink.
     655           0 :     OStoreDirectoryPageObject aPage;
     656           0 :     if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
     657             :     {
     658             :         // Load directory page.
     659           0 :         eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
     660           0 :         if (eErrCode != store_E_None)
     661           0 :             return eErrCode;
     662             : 
     663             :         // Check for directory.
     664           0 :         if (aPage.attrib() & STORE_ATTRIB_ISDIR)
     665             :         {
     666             :             // Ugly, but necessary (backward compatibility).
     667           0 :             aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1));
     668             :         }
     669             :     }
     670             : 
     671             :     // Let 'Source' entry be 'Destination' entry.
     672           0 :     e.m_aKey = aDstKey;
     673             : 
     674             :     // Find 'Destination' NodePage and Index.
     675           0 :     OStoreBTreeNodeObject aDstNode;
     676           0 :     eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this);
     677           0 :     if (eErrCode != store_E_None)
     678           0 :         return eErrCode;
     679             : 
     680             :     // Insert 'Destination' entry.
     681           0 :     PageHolderObject< page > xDstNode (aDstNode.get());
     682           0 :     xDstNode->insert (i + 1, e);
     683             : 
     684           0 :     eErrCode = saveObjectAt (aDstNode, aDstNode.location());
     685           0 :     if (eErrCode != store_E_None)
     686           0 :         return eErrCode;
     687             : 
     688             :     // Check for (not a) hardlink.
     689           0 :     if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
     690             :     {
     691             :         // Modify 'Source' directory page.
     692           0 :         inode_holder_type xNode (aPage.get());
     693             : 
     694             :         // Setup 'Destination' NameBlock.
     695           0 :         sal_Int32 nDstLen = pDstName->length;
     696             :         memcpy (
     697           0 :             &(xNode->m_aNameBlock.m_pData[0]),
     698           0 :             pDstName->buffer, pDstName->length);
     699             :         memset (
     700           0 :             &(xNode->m_aNameBlock.m_pData[nDstLen]),
     701           0 :             0, STORE_MAXIMUM_NAMESIZE - nDstLen);
     702           0 :         aPage.key (e.m_aKey);
     703             : 
     704             :         // Save directory page.
     705           0 :         eErrCode = base::saveObjectAt (aPage, e.m_aLink.location());
     706           0 :         if (eErrCode != store_E_None)
     707           0 :             return eErrCode;
     708             :     }
     709             : 
     710             :     // Remove 'Source' entry.
     711           0 :     e.m_aKey = rSrcKey;
     712           0 :     return remove_Impl (e);
     713             : }
     714             : 
     715             : /*
     716             :  * remove.
     717             :  * Precond: initialized, writeable.
     718             :  */
     719           9 : storeError OStorePageManager::remove (const OStorePageKey &rKey)
     720             : {
     721             :     // Acquire exclusive access.
     722           9 :     osl::MutexGuard aGuard(*this);
     723             : 
     724             :     // Check precond.
     725           9 :     if (!self::isValid())
     726           0 :         return store_E_InvalidAccess;
     727             : 
     728           9 :     if (!base::isWriteable())
     729           0 :         return store_E_AccessViolation;
     730             : 
     731             :     // Find NodePage and index.
     732          18 :     OStoreBTreeNodeObject aNodePage;
     733           9 :     sal_uInt16 i = 0;
     734           9 :     storeError eErrCode = find_lookup (aNodePage, i, rKey);
     735           9 :     if (eErrCode != store_E_None)
     736           0 :         return eErrCode;
     737             : 
     738             :     // Existing entry.
     739          18 :     PageHolderObject< page > xNodePage (aNodePage.get());
     740           9 :     entry e (xNodePage->m_pData[i]);
     741             : 
     742             :     // Check for (not a) hardlink.
     743           9 :     if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
     744             :     {
     745             :         // Load directory page.
     746           9 :         OStoreDirectoryPageObject aPage;
     747           9 :         eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
     748           9 :         if (eErrCode != store_E_None)
     749           0 :             return eErrCode;
     750             : 
     751          18 :         inode_holder_type xNode (aPage.get());
     752             : 
     753             :         // Acquire page write access.
     754           9 :         OStorePageDescriptor aDescr (xNode->m_aDescr);
     755           9 :         eErrCode = base::acquirePage (aDescr, store_AccessReadWrite);
     756           9 :         if (eErrCode != store_E_None)
     757           0 :             return eErrCode;
     758             : 
     759             :         // Check for symbolic link.
     760           9 :         if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
     761             :         {
     762             :             // Ordinary inode. Determine 'Data' scope.
     763           9 :             inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
     764           9 :             if (eScope == inode::SCOPE_EXTERNAL)
     765             :             {
     766             :                 // External 'Data' scope. Truncate all external data pages.
     767           1 :                 eErrCode = aPage.truncate (0, *this);
     768           1 :                 if (eErrCode != store_E_None)
     769           0 :                     return eErrCode;
     770             :             }
     771             : 
     772             :             // Truncate internal data page.
     773           9 :             memset (&(xNode->m_pData[0]), 0, xNode->capacity());
     774           9 :             aPage.dataLength (0);
     775             :         }
     776             : 
     777             :         // Release page write access.
     778           9 :         eErrCode = base::releasePage (aDescr);
     779             : 
     780             :         // Release and free directory page.
     781          18 :         eErrCode = base::free (aPage.location());
     782             :     }
     783             : 
     784             :     // Remove entry.
     785          18 :     return remove_Impl (e);
     786             : }
     787             : 
     788             : /*
     789             :  * RebuildContext.
     790             :  */
     791           0 : struct RebuildContext
     792             : {
     793             :     /** Representation.
     794             :     */
     795             :     rtl::Reference<OStorePageBIOS> m_xBIOS;
     796             :     OStorePageBIOS::ScanContext    m_aCtx;
     797             :     sal_uInt16                     m_nPageSize;
     798             : 
     799             :     /** Construction.
     800             :      */
     801           0 :     RebuildContext()
     802           0 :         : m_xBIOS     (new OStorePageBIOS()),
     803           0 :           m_nPageSize (0)
     804           0 :     {}
     805             : 
     806             :     /** initialize (PageBIOS and ScanContext).
     807             :     */
     808           0 :     storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0)
     809             :     {
     810           0 :         storeError eErrCode = store_E_InvalidParameter;
     811           0 :         if (pLockBytes)
     812             :         {
     813           0 :             m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize);
     814           0 :             eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic);
     815             :         }
     816           0 :         return eErrCode;
     817             :     }
     818             : 
     819             :     /** initialize (ScanContext).
     820             :     */
     821           0 :     storeError initialize (sal_uInt32 nMagic = 0)
     822             :     {
     823           0 :         return m_xBIOS->scanBegin (m_aCtx, nMagic);
     824             :     }
     825             : 
     826             :     /** load (next ScanContext matching page).
     827             :     */
     828           0 :     storeError load (OStorePageObject &rPage)
     829             :     {
     830           0 :         if (m_aCtx.isValid())
     831           0 :             return m_xBIOS->scanNext (m_aCtx, rPage);
     832             :         else
     833           0 :             return store_E_CantSeek;
     834             :     }
     835             : };
     836             : 
     837             : /*
     838             :  * rebuild.
     839             :  * Precond: none.
     840             :  */
     841           0 : storeError OStorePageManager::rebuild (
     842             :     ILockBytes *pSrcLB, ILockBytes *pDstLB)
     843             : {
     844             :     // Acquire exclusive access.
     845           0 :     osl::MutexGuard aGuard(*this);
     846             : 
     847             :     // Check arguments.
     848           0 :     storeError eErrCode = store_E_InvalidParameter;
     849           0 :     if (!(pSrcLB && pDstLB))
     850           0 :         return eErrCode;
     851             : 
     852             :     // Initialize 'Source' rebuild context.
     853           0 :     RebuildContext aCtx;
     854           0 :     eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE);
     855           0 :     if (eErrCode != store_E_None)
     856           0 :         return eErrCode;
     857           0 :     rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS);
     858             : 
     859             :     // Initialize as 'Destination' with 'Source' page size.
     860           0 :     eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize);
     861           0 :     if (eErrCode != store_E_None)
     862           0 :         return eErrCode;
     863             : 
     864             :     // Pass One: Scan 'Source' directory pages.
     865             :     {
     866             :         // Scan 'Source' directory pages.
     867           0 :         OStoreDirectoryPageObject aSrcPage;
     868           0 :         while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None)
     869             :         {
     870           0 :             OStoreDirectoryPageObject aDstPage;
     871           0 :             eErrCode = aDstPage.construct< inode >(base::allocator());
     872           0 :             if (eErrCode != store_E_None)
     873           0 :                 break;
     874             : 
     875           0 :             inode_holder_type xSrcDir (aSrcPage.get());
     876           0 :             inode_holder_type xDstDir (aDstPage.get());
     877             : 
     878             :             // Copy NameBlock @@@ OLD @@@
     879           0 :             memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock));
     880             : 
     881             :             // Obtain 'Source' data length.
     882           0 :             sal_uInt32 nDataLen = aSrcPage.dataLength();
     883           0 :             if (nDataLen > 0)
     884             :             {
     885             :                 // Copy internal data area @@@ OLD @@@
     886           0 :                 memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity());
     887             :             }
     888             : 
     889             :             // Insert 'Destination' directory page.
     890           0 :             eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage);
     891           0 :             if (eErrCode != store_E_None)
     892           0 :                 break;
     893             : 
     894             :             // Check for external data page scope.
     895           0 :             if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL)
     896             :             {
     897             :                 // Initialize 'Destination' data page.
     898             :                 typedef OStoreDataPageData data;
     899           0 :                 PageHolderObject< data > xData;
     900           0 :                 if (!xData.construct(base::allocator()))
     901           0 :                     return store_E_OutOfMemory;
     902             : 
     903             :                 // Determine data page count.
     904             :                 inode::ChunkDescriptor aDescr (
     905           0 :                     nDataLen - xDstDir->capacity(), xData->capacity());
     906             : 
     907           0 :                 sal_uInt32 i, n = aDescr.m_nPage;
     908           0 :                 if (aDescr.m_nOffset) n += 1;
     909             : 
     910             :                 // Copy data pages.
     911           0 :                 OStoreDataPageObject aData;
     912           0 :                 for (i = 0; i < n; i++)
     913             :                 {
     914             :                     // Read 'Source' data page.
     915           0 :                     osl::MutexGuard aSrcGuard (*xSrcBIOS);
     916             : 
     917           0 :                     eErrCode = aSrcPage.read (i, aData, *xSrcBIOS);
     918           0 :                     if (eErrCode != store_E_None)
     919           0 :                         continue;
     920             : 
     921             :                     // Write 'Destination' data page. @@@ READONLY @@@
     922           0 :                     (void) aDstPage.write (i, aData, *this);
     923           0 :                 }
     924             :             }
     925             : 
     926             :             // Update 'Destination' directory page.
     927           0 :             aDstPage.dataLength (nDataLen);
     928           0 :             (void) base::saveObjectAt (aDstPage, aDstPage.location());
     929           0 :         }
     930             : 
     931             :         // Save directory scan results.
     932           0 :         flush();
     933             :     }
     934             : 
     935             :     // Pass Two: Scan 'Source' BTree nodes.
     936             :     {
     937             :         // Re-start 'Source' rebuild context.
     938           0 :         aCtx.initialize (STORE_MAGIC_BTREENODE);
     939             : 
     940             :         // Scan 'Source' BTree nodes.
     941           0 :         OStoreBTreeNodeObject aNode;
     942           0 :         while ((eErrCode = aCtx.load(aNode)) == store_E_None)
     943             :         {
     944             :             // Check for leaf node.
     945           0 :             PageHolderObject< page > xNode (aNode.get());
     946           0 :             if (xNode->depth() == 0)
     947             :             {
     948           0 :                 sal_uInt16 i, n = xNode->usageCount();
     949           0 :                 for (i = 0; i < n; i++)
     950             :                 {
     951           0 :                     entry e (xNode->m_pData[i]);
     952             : 
     953             :                     // Check for Hard link.
     954           0 :                     if (e.m_nAttrib & STORE_ATTRIB_ISLINK)
     955             :                     {
     956             :                         // Load the hard link destination.
     957           0 :                         OStoreDirectoryPageObject aSrcPage;
     958           0 :                         eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location());
     959           0 :                         if (eErrCode == store_E_None)
     960             :                         {
     961           0 :                             OStorePageKey aDstKey (aSrcPage.key());
     962           0 :                             link (e.m_aKey, aDstKey);
     963             :                         }
     964           0 :                         e.m_nAttrib &= ~STORE_ATTRIB_ISLINK;
     965             :                     }
     966             : 
     967           0 :                     if (e.m_nAttrib)
     968             :                     {
     969             :                         // Ordinary attributes.
     970           0 :                         sal_uInt32 nAttrib = 0;
     971           0 :                         attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib);
     972             :                     }
     973             :                 }
     974             :             }
     975           0 :         }
     976             : 
     977             :         // Save BTree node scan results.
     978           0 :         flush();
     979             :     }
     980             : 
     981             :     // Done.
     982           0 :     return store_E_None;
     983             : }
     984             : 
     985             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11