Branch libreoffice-5-0-4
[LibreOffice.git] / store / source / storpage.cxx
blobd6b186c074e5e7de28b92e5b2f86e16bbcef4858
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "storpage.hxx"
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"
29 #include "store/types.h"
31 #include "object.hxx"
32 #include "lockbyte.hxx"
34 #include "storbase.hxx"
35 #include "stordata.hxx"
36 #include "stortree.hxx"
38 using namespace store;
40 /*========================================================================
42 * OStorePageManager implementation.
44 *======================================================================*/
45 const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
48 * OStorePageManager.
50 OStorePageManager::OStorePageManager()
55 * ~OStorePageManager.
57 OStorePageManager::~OStorePageManager()
62 * isKindOf.
64 bool OStorePageManager::isKindOf (sal_uInt32 nTypeId)
66 return (nTypeId == m_nTypeId);
70 * initialize (two-phase construction).
71 * Precond: none.
73 storeError OStorePageManager::initialize (
74 ILockBytes * pLockBytes,
75 storeAccessMode eAccessMode,
76 sal_uInt16 & rnPageSize)
78 // Acquire exclusive access.
79 osl::MutexGuard aGuard(*this);
81 // Check arguments.
82 if (!pLockBytes)
83 return store_E_InvalidParameter;
85 // Initialize base.
86 storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
87 if (eErrCode != store_E_None)
88 return eErrCode;
90 // Check for (not) writeable.
91 if (!base::isWriteable())
93 // Readonly. Load RootNode.
94 return base::loadObjectAt (m_aRoot, rnPageSize);
97 // Writeable. Load or Create RootNode.
98 eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
99 if (eErrCode == store_E_Pending)
101 // Creation notification.
102 PageHolderObject< page > xRoot (m_aRoot.get());
104 // Pre-allocate left most entry (ugly, but we can't insert to left).
105 OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
106 xRoot->insert (0, entry(aKey));
108 // Save RootNode.
109 eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
112 // Done.
113 return eErrCode;
117 * find_lookup (w/o split()).
118 * Internal: Precond: initialized, readable, exclusive access.
120 storeError OStorePageManager::find_lookup (
121 OStoreBTreeNodeObject & rNode,
122 sal_uInt16 & rIndex,
123 OStorePageKey const & rKey)
125 // Find Node and Index.
126 storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
127 if (eErrCode != store_E_None)
128 return eErrCode;
130 // Greater or Equal.
131 PageHolderObject< page > xPage (rNode.get());
132 SAL_WARN_IF(rIndex >= xPage->usageCount(), "store", "store::PageManager::find_lookup(): logic error");
133 entry e (xPage->m_pData[rIndex]);
135 // Check for exact match.
136 if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
138 // Page not present.
139 return store_E_NotExists;
142 // Check address.
143 if (e.m_aLink.location() == STORE_PAGE_NULL)
145 // Page not present.
146 return store_E_NotExists;
149 return store_E_None;
153 * remove_Impl (possibly down from root).
154 * Internal: Precond: initialized, writeable, exclusive access.
157 storeError OStorePageManager::remove_Impl (entry & rEntry)
159 OStoreBTreeNodeObject aNode (m_aRoot.get());
161 // Check current page index.
162 PageHolderObject< page > xPage (aNode.get());
163 sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
164 if (!(i < n))
166 // Path to entry not exists (Must not happen(?)).
167 return store_E_NotExists;
170 // Compare entry.
171 entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
173 // Iterate down until equal match.
174 while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
176 // Check link address.
177 sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
178 if (nAddr == STORE_PAGE_NULL)
180 // Path to entry not exists (Must not happen(?)).
181 return store_E_NotExists;
184 // Load link page.
185 storeError eErrCode = loadObjectAt (aNode, nAddr);
186 if (eErrCode != store_E_None)
187 return eErrCode;
189 PageHolderObject< page > xNext (aNode.get());
190 xNext.swap (xPage);
192 // Check index.
193 i = xPage->find (rEntry), n = xPage->usageCount();
194 if (!(i < n))
196 // Path to entry not exists (Must not happen(?)).
197 return store_E_NotExists;
200 // Compare entry.
201 result = rEntry.compare (xPage->m_pData[i]);
204 SAL_WARN_IF(
205 result == entry::COMPARE_LESS,
206 "store",
207 "OStorePageManager::remove(): find failed");
209 // Check entry comparison.
210 if (result == entry::COMPARE_LESS)
212 // Must not happen.
213 return store_E_Unknown;
216 // Remove down from current page (recursive).
217 return aNode.remove (i, rEntry, *this);
221 * namei.
222 * Precond: none (static).
224 storeError OStorePageManager::namei (
225 const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
227 // Check parameter.
228 if (!(pPath && pName))
229 return store_E_InvalidParameter;
231 // Check name length.
232 if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
233 return store_E_NameTooLong;
235 // Transform pathname into key.
236 rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
237 rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
239 // Done.
240 return store_E_None;
244 * iget.
245 * Precond: initialized.
247 storeError OStorePageManager::iget (
248 OStoreDirectoryPageObject & rPage,
249 sal_uInt32 nAttrib,
250 const rtl_String * pPath,
251 const rtl_String * pName,
252 storeAccessMode eMode)
254 // Acquire exclusive access.
255 osl::MutexGuard aGuard(*this);
257 // Check precond.
258 if (!self::isValid())
259 return store_E_InvalidAccess;
261 // Setup inode page key.
262 OStorePageKey aKey;
263 storeError eErrCode = namei (pPath, pName, aKey);
264 if (eErrCode != store_E_None)
265 return eErrCode;
267 // Check for directory.
268 if (nAttrib & STORE_ATTRIB_ISDIR)
270 // Ugly, but necessary (backward compatibility).
271 aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
274 // Load inode page.
275 eErrCode = load_dirpage_Impl (aKey, rPage);
276 if (eErrCode != store_E_None)
278 // Check mode and reason.
279 if (eErrCode != store_E_NotExists)
280 return eErrCode;
282 if (eMode == store_AccessReadWrite)
283 return store_E_NotExists;
284 if (eMode == store_AccessReadOnly)
285 return store_E_NotExists;
287 if (!base::isWriteable())
288 return store_E_AccessViolation;
290 // Create inode page.
291 eErrCode = rPage.construct< inode >(base::allocator());
292 if (eErrCode != store_E_None)
293 return eErrCode;
295 // Setup inode nameblock.
296 PageHolderObject< inode > xPage (rPage.get());
298 rPage.key (aKey);
299 rPage.attrib (nAttrib);
301 memcpy (
302 &(xPage->m_aNameBlock.m_pData[0]),
303 pName->buffer, pName->length);
305 // Save inode page.
306 eErrCode = save_dirpage_Impl (aKey, rPage);
307 if (eErrCode != store_E_None)
308 return eErrCode;
311 // Check for symbolic link.
312 if (rPage.attrib() & STORE_ATTRIB_ISLINK)
314 // Obtain 'Destination' page key.
315 PageHolderObject< inode > xPage (rPage.get());
316 OStorePageKey aDstKey;
317 memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
319 // Load 'Destination' inode.
320 eErrCode = load_dirpage_Impl (aDstKey, rPage);
321 if (eErrCode != store_E_None)
322 return eErrCode;
325 // Done.
326 return store_E_None;
330 * iterate.
331 * Precond: initialized.
332 * ToDo: skip hardlink entries.
334 storeError OStorePageManager::iterate (
335 OStorePageKey & rKey,
336 OStorePageLink & rLink,
337 sal_uInt32 & rAttrib)
339 // Acquire exclusive access.
340 osl::MutexGuard aGuard(*this);
342 // Check precond.
343 if (!self::isValid())
344 return store_E_InvalidAccess;
346 // Find NodePage and Index.
347 OStoreBTreeNodeObject aNode;
348 sal_uInt16 i = 0;
349 storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
350 if (eErrCode != store_E_None)
351 return eErrCode;
353 // GreaterEqual. Found next entry.
354 PageHolderObject< page > xNode (aNode.get());
355 entry e (xNode->m_pData[i]);
357 // Setup result.
358 rKey = e.m_aKey;
359 rLink = e.m_aLink;
360 rAttrib = store::ntohl(e.m_nAttrib);
362 // Done.
363 return store_E_None;
367 * load => private: iget() @@@
368 * Internal: Precond: initialized, exclusive access.
370 storeError OStorePageManager::load_dirpage_Impl (
371 const OStorePageKey &rKey,
372 OStoreDirectoryPageObject &rPage)
374 // Find Node and Index.
375 OStoreBTreeNodeObject aNode;
376 sal_uInt16 i = 0;
377 storeError eErrCode = find_lookup (aNode, i, rKey);
378 if (eErrCode != store_E_None)
379 return eErrCode;
381 // Existing entry. Load page.
382 PageHolderObject< page > xNode (aNode.get());
383 entry e (xNode->m_pData[i]);
384 return loadObjectAt (rPage, e.m_aLink.location());
388 * save => private: iget(), rebuild() @@@
389 * Internal: Precond: initialized, writeable, exclusive access.
391 storeError OStorePageManager::save_dirpage_Impl (
392 const OStorePageKey &rKey,
393 OStoreDirectoryPageObject &rPage)
395 // Find NodePage and Index.
396 node aNode;
397 sal_uInt16 i = 0;
399 storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
400 PageHolderObject< page > xNode (aNode.get());
401 if (eErrCode != store_E_None)
403 if (eErrCode != store_E_AlreadyExists)
404 return eErrCode;
406 // Existing entry.
407 entry e (xNode->m_pData[i]);
408 if (e.m_aLink.location() != STORE_PAGE_NULL)
410 // Save page to existing location.
411 return saveObjectAt (rPage, e.m_aLink.location());
414 // Allocate page.
415 eErrCode = base::allocate (rPage);
416 if (eErrCode != store_E_None)
417 return eErrCode;
419 // Update page location.
420 xNode->m_pData[i].m_aLink = rPage.location();
422 // Save modified NodePage.
423 return saveObjectAt (aNode, aNode.location());
426 // Allocate page.
427 eErrCode = base::allocate (rPage);
428 if (eErrCode != store_E_None)
429 return eErrCode;
431 // Insert.
432 OStorePageLink aLink (rPage.location());
433 xNode->insert (i + 1, entry (rKey, aLink));
435 // Save modified NodePage.
436 return saveObjectAt (aNode, aNode.location());
440 * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)].
441 * Precond: initialized.
443 storeError OStorePageManager::attrib (
444 const OStorePageKey &rKey,
445 sal_uInt32 nMask1,
446 sal_uInt32 nMask2,
447 sal_uInt32 &rAttrib)
449 // Acquire exclusive access.
450 osl::MutexGuard aGuard(*this);
452 // Check precond.
453 if (!self::isValid())
454 return store_E_InvalidAccess;
456 // Find NodePage and index.
457 OStoreBTreeNodeObject aNode;
458 sal_uInt16 i = 0;
459 storeError eErrCode = find_lookup (aNode, i, rKey);
460 if (eErrCode != store_E_None)
461 return eErrCode;
463 // Existing entry.
464 PageHolderObject< page > xNode (aNode.get());
465 entry e (xNode->m_pData[i]);
466 if (nMask1 != nMask2)
468 // Evaluate new attributes.
469 sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib);
471 nAttrib &= ~nMask1;
472 nAttrib |= nMask2;
474 if (store::htonl(nAttrib) != e.m_nAttrib)
476 // Check access mode.
477 if (base::isWriteable())
479 // Set new attributes.
480 e.m_nAttrib = store::htonl(nAttrib);
481 xNode->m_pData[i] = e;
483 // Save modified NodePage.
484 eErrCode = saveObjectAt (aNode, aNode.location());
486 else
488 // Access denied.
489 eErrCode = store_E_AccessViolation;
494 // Obtain current attributes.
495 rAttrib = store::ntohl(e.m_nAttrib);
496 return eErrCode;
500 * link (insert 'Source' as hardlink to 'Destination').
501 * Precond: initialized, writeable.
503 storeError OStorePageManager::link (
504 const OStorePageKey &rSrcKey,
505 const OStorePageKey &rDstKey)
507 // Acquire exclusive access.
508 osl::MutexGuard aGuard(*this);
510 // Check precond.
511 if (!self::isValid())
512 return store_E_InvalidAccess;
514 if (!base::isWriteable())
515 return store_E_AccessViolation;
517 // Find 'Destination' NodePage and Index.
518 OStoreBTreeNodeObject aDstNode;
519 sal_uInt16 i = 0;
520 storeError eErrCode = find_lookup (aDstNode, i, rDstKey);
521 if (eErrCode != store_E_None)
522 return eErrCode;
524 // Existing 'Destination' entry.
525 PageHolderObject< page > xDstNode (aDstNode.get());
526 entry e (xDstNode->m_pData[i]);
527 OStorePageLink aDstLink (e.m_aLink);
529 // Find 'Source' NodePage and Index.
530 OStoreBTreeNodeObject aSrcNode;
531 eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this);
532 if (eErrCode != store_E_None)
533 return eErrCode;
535 // Insert 'Source' entry.
536 PageHolderObject< page > xSrcNode (aSrcNode.get());
537 xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK));
538 return saveObjectAt (aSrcNode, aSrcNode.location());
542 * symlink (insert 'Source' DirectoryPage as symlink to 'Destination').
543 * Precond: initialized, writeable.
545 storeError OStorePageManager::symlink (
546 const rtl_String *pSrcPath,
547 const rtl_String *pSrcName,
548 const OStorePageKey &rDstKey)
550 // Acquire exclusive access.
551 osl::MutexGuard aGuard(*this);
553 // Check precond.
554 if (!self::isValid())
555 return store_E_InvalidAccess;
557 if (!base::isWriteable())
558 return store_E_AccessViolation;
560 // Check 'Source' parameter.
561 storeError eErrCode = store_E_InvalidParameter;
562 if (!(pSrcPath && pSrcName))
563 return eErrCode;
565 // Setup 'Source' page key.
566 OStorePageKey aSrcKey;
567 eErrCode = namei (pSrcPath, pSrcName, aSrcKey);
568 if (eErrCode != store_E_None)
569 return eErrCode;
571 // Find 'Source' NodePage and Index.
572 OStoreBTreeNodeObject aSrcNode;
573 sal_uInt16 i = 0;
574 eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this);
575 if (eErrCode != store_E_None)
576 return eErrCode;
578 // Initialize directory page.
579 OStoreDirectoryPageObject aPage;
580 eErrCode = aPage.construct< inode >(base::allocator());
581 if (eErrCode != store_E_None)
582 return eErrCode;
584 // Setup as 'Source' directory page.
585 inode_holder_type xNode (aPage.get());
586 aPage.key (aSrcKey);
587 memcpy (
588 &(xNode->m_aNameBlock.m_pData[0]),
589 pSrcName->buffer, pSrcName->length);
591 // Store 'Destination' page key.
592 OStorePageKey aDstKey (rDstKey);
593 memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey));
595 // Mark 'Source' as symbolic link to 'Destination'.
596 aPage.attrib (STORE_ATTRIB_ISLINK);
597 aPage.dataLength (sal_uInt32(sizeof(aDstKey)));
599 // Allocate and save 'Source' directory page.
600 eErrCode = base::allocate (aPage);
601 if (eErrCode != store_E_None)
602 return eErrCode;
604 // Insert 'Source' entry.
605 PageHolderObject< page > xSrcNode (aSrcNode.get());
606 OStorePageLink aSrcLink (aPage.location());
607 xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink));
609 // Save modified NodePage.
610 return saveObjectAt (aSrcNode, aSrcNode.location());
614 * rename.
615 * Precond: initialized, writeable.
617 storeError OStorePageManager::rename (
618 const OStorePageKey &rSrcKey,
619 const rtl_String *pDstPath,
620 const rtl_String *pDstName)
622 // Acquire exclusive access.
623 osl::MutexGuard aGuard(*this);
625 // Check precond.
626 if (!self::isValid())
627 return store_E_InvalidAccess;
629 if (!base::isWriteable())
630 return store_E_AccessViolation;
632 // Check 'Destination' parameter.
633 storeError eErrCode = store_E_InvalidParameter;
634 if (!(pDstPath && pDstName))
635 return eErrCode;
637 // Setup 'Destination' page key.
638 OStorePageKey aDstKey;
639 eErrCode = namei (pDstPath, pDstName, aDstKey);
640 if (eErrCode != store_E_None)
641 return eErrCode;
643 // Find 'Source' NodePage and Index.
644 OStoreBTreeNodeObject aSrcNode;
645 sal_uInt16 i = 0;
646 eErrCode = find_lookup (aSrcNode, i, rSrcKey);
647 if (eErrCode != store_E_None)
648 return eErrCode;
650 // Existing 'Source' entry.
651 PageHolderObject< page > xSrcNode (aSrcNode.get());
652 entry e (xSrcNode->m_pData[i]);
654 // Check for (not a) hardlink.
655 OStoreDirectoryPageObject aPage;
656 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
658 // Load directory page.
659 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
660 if (eErrCode != store_E_None)
661 return eErrCode;
663 // Check for directory.
664 if (aPage.attrib() & STORE_ATTRIB_ISDIR)
666 // Ugly, but necessary (backward compatibility).
667 aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1));
671 // Let 'Source' entry be 'Destination' entry.
672 e.m_aKey = aDstKey;
674 // Find 'Destination' NodePage and Index.
675 OStoreBTreeNodeObject aDstNode;
676 eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this);
677 if (eErrCode != store_E_None)
678 return eErrCode;
680 // Insert 'Destination' entry.
681 PageHolderObject< page > xDstNode (aDstNode.get());
682 xDstNode->insert (i + 1, e);
684 eErrCode = saveObjectAt (aDstNode, aDstNode.location());
685 if (eErrCode != store_E_None)
686 return eErrCode;
688 // Check for (not a) hardlink.
689 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
691 // Modify 'Source' directory page.
692 inode_holder_type xNode (aPage.get());
694 // Setup 'Destination' NameBlock.
695 sal_Int32 nDstLen = pDstName->length;
696 memcpy (
697 &(xNode->m_aNameBlock.m_pData[0]),
698 pDstName->buffer, pDstName->length);
699 memset (
700 &(xNode->m_aNameBlock.m_pData[nDstLen]),
701 0, STORE_MAXIMUM_NAMESIZE - nDstLen);
702 aPage.key (e.m_aKey);
704 // Save directory page.
705 eErrCode = base::saveObjectAt (aPage, e.m_aLink.location());
706 if (eErrCode != store_E_None)
707 return eErrCode;
710 // Remove 'Source' entry.
711 e.m_aKey = rSrcKey;
712 return remove_Impl (e);
716 * remove.
717 * Precond: initialized, writeable.
719 storeError OStorePageManager::remove (const OStorePageKey &rKey)
721 // Acquire exclusive access.
722 osl::MutexGuard aGuard(*this);
724 // Check precond.
725 if (!self::isValid())
726 return store_E_InvalidAccess;
728 if (!base::isWriteable())
729 return store_E_AccessViolation;
731 // Find NodePage and index.
732 OStoreBTreeNodeObject aNodePage;
733 sal_uInt16 i = 0;
734 storeError eErrCode = find_lookup (aNodePage, i, rKey);
735 if (eErrCode != store_E_None)
736 return eErrCode;
738 // Existing entry.
739 PageHolderObject< page > xNodePage (aNodePage.get());
740 entry e (xNodePage->m_pData[i]);
742 // Check for (not a) hardlink.
743 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
745 // Load directory page.
746 OStoreDirectoryPageObject aPage;
747 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
748 if (eErrCode != store_E_None)
749 return eErrCode;
751 inode_holder_type xNode (aPage.get());
753 // Acquire page write access.
754 OStorePageDescriptor aDescr (xNode->m_aDescr);
755 eErrCode = base::acquirePage (aDescr, store_AccessReadWrite);
756 if (eErrCode != store_E_None)
757 return eErrCode;
759 // Check for symbolic link.
760 if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
762 // Ordinary inode. Determine 'Data' scope.
763 inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
764 if (eScope == inode::SCOPE_EXTERNAL)
766 // External 'Data' scope. Truncate all external data pages.
767 eErrCode = aPage.truncate (0, *this);
768 if (eErrCode != store_E_None)
769 return eErrCode;
772 // Truncate internal data page.
773 memset (&(xNode->m_pData[0]), 0, xNode->capacity());
774 aPage.dataLength (0);
777 // Release page write access.
778 eErrCode = base::releasePage (aDescr);
780 // Release and free directory page.
781 eErrCode = base::free (aPage.location());
784 // Remove entry.
785 return remove_Impl (e);
789 * RebuildContext.
791 struct RebuildContext
793 /** Representation.
795 rtl::Reference<OStorePageBIOS> m_xBIOS;
796 OStorePageBIOS::ScanContext m_aCtx;
797 sal_uInt16 m_nPageSize;
799 /** Construction.
801 RebuildContext()
802 : m_xBIOS (new OStorePageBIOS()),
803 m_nPageSize (0)
806 /** initialize (PageBIOS and ScanContext).
808 storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0)
810 storeError eErrCode = store_E_InvalidParameter;
811 if (pLockBytes)
813 m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize);
814 eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic);
816 return eErrCode;
819 /** initialize (ScanContext).
821 storeError initialize (sal_uInt32 nMagic = 0)
823 return m_xBIOS->scanBegin (m_aCtx, nMagic);
826 /** load (next ScanContext matching page).
828 storeError load (OStorePageObject &rPage)
830 if (m_aCtx.isValid())
831 return m_xBIOS->scanNext (m_aCtx, rPage);
832 else
833 return store_E_CantSeek;
838 * rebuild.
839 * Precond: none.
841 storeError OStorePageManager::rebuild (
842 ILockBytes *pSrcLB, ILockBytes *pDstLB)
844 // Acquire exclusive access.
845 osl::MutexGuard aGuard(*this);
847 // Check arguments.
848 storeError eErrCode = store_E_InvalidParameter;
849 if (!(pSrcLB && pDstLB))
850 return eErrCode;
852 // Initialize 'Source' rebuild context.
853 RebuildContext aCtx;
854 eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE);
855 if (eErrCode != store_E_None)
856 return eErrCode;
857 rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS);
859 // Initialize as 'Destination' with 'Source' page size.
860 eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize);
861 if (eErrCode != store_E_None)
862 return eErrCode;
864 // Pass One: Scan 'Source' directory pages.
866 // Scan 'Source' directory pages.
867 OStoreDirectoryPageObject aSrcPage;
868 while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None)
870 OStoreDirectoryPageObject aDstPage;
871 eErrCode = aDstPage.construct< inode >(base::allocator());
872 if (eErrCode != store_E_None)
873 break;
875 inode_holder_type xSrcDir (aSrcPage.get());
876 inode_holder_type xDstDir (aDstPage.get());
878 // Copy NameBlock @@@ OLD @@@
879 memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock));
881 // Obtain 'Source' data length.
882 sal_uInt32 nDataLen = aSrcPage.dataLength();
883 if (nDataLen > 0)
885 // Copy internal data area @@@ OLD @@@
886 memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity());
889 // Insert 'Destination' directory page.
890 eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage);
891 if (eErrCode != store_E_None)
892 break;
894 // Check for external data page scope.
895 if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL)
897 // Initialize 'Destination' data page.
898 typedef OStoreDataPageData data;
899 PageHolderObject< data > xData;
900 if (!xData.construct(base::allocator()))
901 return store_E_OutOfMemory;
903 // Determine data page count.
904 inode::ChunkDescriptor aDescr (
905 nDataLen - xDstDir->capacity(), xData->capacity());
907 sal_uInt32 i, n = aDescr.m_nPage;
908 if (aDescr.m_nOffset) n += 1;
910 // Copy data pages.
911 OStoreDataPageObject aData;
912 for (i = 0; i < n; i++)
914 // Read 'Source' data page.
915 osl::MutexGuard aSrcGuard (*xSrcBIOS);
917 eErrCode = aSrcPage.read (i, aData, *xSrcBIOS);
918 if (eErrCode != store_E_None)
919 continue;
921 // Write 'Destination' data page. @@@ READONLY @@@
922 (void) aDstPage.write (i, aData, *this);
926 // Update 'Destination' directory page.
927 aDstPage.dataLength (nDataLen);
928 (void) base::saveObjectAt (aDstPage, aDstPage.location());
931 // Save directory scan results.
932 flush();
935 // Pass Two: Scan 'Source' BTree nodes.
937 // Re-start 'Source' rebuild context.
938 aCtx.initialize (STORE_MAGIC_BTREENODE);
940 // Scan 'Source' BTree nodes.
941 OStoreBTreeNodeObject aNode;
942 while ((eErrCode = aCtx.load(aNode)) == store_E_None)
944 // Check for leaf node.
945 PageHolderObject< page > xNode (aNode.get());
946 if (xNode->depth() == 0)
948 sal_uInt16 i, n = xNode->usageCount();
949 for (i = 0; i < n; i++)
951 entry e (xNode->m_pData[i]);
953 // Check for Hard link.
954 if (e.m_nAttrib & STORE_ATTRIB_ISLINK)
956 // Load the hard link destination.
957 OStoreDirectoryPageObject aSrcPage;
958 eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location());
959 if (eErrCode == store_E_None)
961 OStorePageKey aDstKey (aSrcPage.key());
962 link (e.m_aKey, aDstKey);
964 e.m_nAttrib &= ~STORE_ATTRIB_ISLINK;
967 if (e.m_nAttrib)
969 // Ordinary attributes.
970 sal_uInt32 nAttrib = 0;
971 attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib);
977 // Save BTree node scan results.
978 flush();
981 // Done.
982 return store_E_None;
985 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */