Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / store / source / storpage.cxx
blobc62cd2a8a92761a7b6c792b863b7c79cd3428203
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "storpage.hxx"
32 #include "sal/types.h"
33 #include "rtl/string.h"
34 #include "rtl/ref.hxx"
35 #include "osl/diagnose.h"
36 #include "osl/mutex.hxx"
38 #include "store/types.h"
40 #include "object.hxx"
41 #include "lockbyte.hxx"
43 #include "storbase.hxx"
44 #include "stordata.hxx"
45 #include "stortree.hxx"
47 using namespace store;
49 /*========================================================================
51 * OStorePageManager implementation.
53 *======================================================================*/
54 const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
57 * OStorePageManager.
59 OStorePageManager::OStorePageManager (void)
64 * ~OStorePageManager.
66 OStorePageManager::~OStorePageManager (void)
71 * isKindOf.
73 sal_Bool SAL_CALL OStorePageManager::isKindOf (sal_uInt32 nTypeId)
75 return (nTypeId == m_nTypeId);
79 * initialize (two-phase construction).
80 * Precond: none.
82 storeError OStorePageManager::initialize (
83 ILockBytes * pLockBytes,
84 storeAccessMode eAccessMode,
85 sal_uInt16 & rnPageSize)
87 // Acquire exclusive access.
88 osl::MutexGuard aGuard(*this);
90 // Check arguments.
91 if (!pLockBytes)
92 return store_E_InvalidParameter;
94 // Initialize base.
95 storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
96 if (eErrCode != store_E_None)
97 return eErrCode;
99 // Check for (not) writeable.
100 if (!base::isWriteable())
102 // Readonly. Load RootNode.
103 return base::loadObjectAt (m_aRoot, rnPageSize);
106 // Writeable. Load or Create RootNode.
107 eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
108 if (eErrCode == store_E_Pending)
110 // Creation notification.
111 PageHolderObject< page > xRoot (m_aRoot.get());
113 // Pre-allocate left most entry (ugly, but we can't insert to left).
114 OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
115 xRoot->insert (0, entry(aKey));
117 // Save RootNode.
118 eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
121 // Done.
122 return eErrCode;
126 * find_lookup (w/o split()).
127 * Internal: Precond: initialized, readable, exclusive access.
129 storeError OStorePageManager::find_lookup (
130 OStoreBTreeNodeObject & rNode,
131 sal_uInt16 & rIndex,
132 OStorePageKey const & rKey)
134 // Find Node and Index.
135 storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
136 if (eErrCode != store_E_None)
137 return eErrCode;
139 // Greater or Equal.
140 PageHolderObject< page > xPage (rNode.get());
141 OSL_POSTCOND(rIndex < xPage->usageCount(), "store::PageManager::find_lookup(): logic error");
142 entry e (xPage->m_pData[rIndex]);
144 // Check for exact match.
145 if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
147 // Page not present.
148 return store_E_NotExists;
151 // Check address.
152 if (e.m_aLink.location() == STORE_PAGE_NULL)
154 // Page not present.
155 return store_E_NotExists;
158 return store_E_None;
162 * remove_Impl (possibly down from root).
163 * Internal: Precond: initialized, writeable, exclusive access.
166 storeError OStorePageManager::remove_Impl (entry & rEntry)
168 OStoreBTreeNodeObject aNode (m_aRoot.get());
170 // Check current page index.
171 PageHolderObject< page > xPage (aNode.get());
172 sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
173 if (!(i < n))
175 // Path to entry not exists (Must not happen(?)).
176 return store_E_NotExists;
179 // Compare entry.
180 entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
182 // Iterate down until equal match.
183 while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
185 // Check link address.
186 sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
187 if (nAddr == STORE_PAGE_NULL)
189 // Path to entry not exists (Must not happen(?)).
190 return store_E_NotExists;
193 // Load link page.
194 storeError eErrCode = loadObjectAt (aNode, nAddr);
195 if (eErrCode != store_E_None)
196 return eErrCode;
198 PageHolderObject< page > xNext (aNode.get());
199 xNext.swap (xPage);
201 // Check index.
202 i = xPage->find (rEntry), n = xPage->usageCount();
203 if (!(i < n))
205 // Path to entry not exists (Must not happen(?)).
206 return store_E_NotExists;
209 // Compare entry.
210 result = rEntry.compare (xPage->m_pData[i]);
213 OSL_POSTCOND(
214 result != entry::COMPARE_LESS,
215 "OStorePageManager::remove(): find failed");
217 // Check entry comparison.
218 if (result == entry::COMPARE_LESS)
220 // Must not happen.
221 return store_E_Unknown;
224 // Remove down from current page (recursive).
225 return aNode.remove (i, rEntry, *this);
229 * namei.
230 * Precond: none (static).
232 storeError OStorePageManager::namei (
233 const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
235 // Check parameter.
236 if (!(pPath && pName))
237 return store_E_InvalidParameter;
239 // Check name length.
240 if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
241 return store_E_NameTooLong;
243 // Transform pathname into key.
244 rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
245 rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
247 // Done.
248 return store_E_None;
252 * iget.
253 * Precond: initialized.
255 storeError OStorePageManager::iget (
256 OStoreDirectoryPageObject & rPage,
257 sal_uInt32 nAttrib,
258 const rtl_String * pPath,
259 const rtl_String * pName,
260 storeAccessMode eMode)
262 // Acquire exclusive access.
263 osl::MutexGuard aGuard(*this);
265 // Check precond.
266 if (!self::isValid())
267 return store_E_InvalidAccess;
269 // Setup inode page key.
270 OStorePageKey aKey;
271 storeError eErrCode = namei (pPath, pName, aKey);
272 if (eErrCode != store_E_None)
273 return eErrCode;
275 // Check for directory.
276 if (nAttrib & STORE_ATTRIB_ISDIR)
278 // Ugly, but necessary (backward compatibility).
279 aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
282 // Load inode page.
283 eErrCode = load_dirpage_Impl (aKey, rPage);
284 if (eErrCode != store_E_None)
286 // Check mode and reason.
287 if (eErrCode != store_E_NotExists)
288 return eErrCode;
290 if (eMode == store_AccessReadWrite)
291 return store_E_NotExists;
292 if (eMode == store_AccessReadOnly)
293 return store_E_NotExists;
295 if (!base::isWriteable())
296 return store_E_AccessViolation;
298 // Create inode page.
299 eErrCode = rPage.construct< inode >(base::allocator());
300 if (eErrCode != store_E_None)
301 return eErrCode;
303 // Setup inode nameblock.
304 PageHolderObject< inode > xPage (rPage.get());
306 rPage.key (aKey);
307 rPage.attrib (nAttrib);
309 memcpy (
310 &(xPage->m_aNameBlock.m_pData[0]),
311 pName->buffer, pName->length);
313 // Save inode page.
314 eErrCode = save_dirpage_Impl (aKey, rPage);
315 if (eErrCode != store_E_None)
316 return eErrCode;
319 // Check for symbolic link.
320 if (rPage.attrib() & STORE_ATTRIB_ISLINK)
322 // Obtain 'Destination' page key.
323 PageHolderObject< inode > xPage (rPage.get());
324 OStorePageKey aDstKey;
325 memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
327 // Load 'Destination' inode.
328 eErrCode = load_dirpage_Impl (aDstKey, rPage);
329 if (eErrCode != store_E_None)
330 return eErrCode;
333 // Done.
334 return store_E_None;
338 * iterate.
339 * Precond: initialized.
340 * ToDo: skip hardlink entries.
342 storeError OStorePageManager::iterate (
343 OStorePageKey & rKey,
344 OStorePageLink & rLink,
345 sal_uInt32 & rAttrib)
347 // Acquire exclusive access.
348 osl::MutexGuard aGuard(*this);
350 // Check precond.
351 if (!self::isValid())
352 return store_E_InvalidAccess;
354 // Find NodePage and Index.
355 OStoreBTreeNodeObject aNode;
356 sal_uInt16 i = 0;
357 storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
358 if (eErrCode != store_E_None)
359 return eErrCode;
361 // GreaterEqual. Found next entry.
362 PageHolderObject< page > xNode (aNode.get());
363 entry e (xNode->m_pData[i]);
365 // Setup result.
366 rKey = e.m_aKey;
367 rLink = e.m_aLink;
368 rAttrib = store::ntohl(e.m_nAttrib);
370 // Done.
371 return store_E_None;
375 * load => private: iget() @@@
376 * Internal: Precond: initialized, exclusive access.
378 storeError OStorePageManager::load_dirpage_Impl (
379 const OStorePageKey &rKey,
380 OStoreDirectoryPageObject &rPage)
382 // Find Node and Index.
383 OStoreBTreeNodeObject aNode;
384 sal_uInt16 i = 0;
385 storeError eErrCode = find_lookup (aNode, i, rKey);
386 if (eErrCode != store_E_None)
387 return eErrCode;
389 // Existing entry. Load page.
390 PageHolderObject< page > xNode (aNode.get());
391 entry e (xNode->m_pData[i]);
392 return loadObjectAt (rPage, e.m_aLink.location());
396 * save => private: iget(), rebuild() @@@
397 * Internal: Precond: initialized, writeable, exclusive access.
399 storeError OStorePageManager::save_dirpage_Impl (
400 const OStorePageKey &rKey,
401 OStoreDirectoryPageObject &rPage)
403 // Find NodePage and Index.
404 node aNode;
405 sal_uInt16 i = 0;
407 storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
408 PageHolderObject< page > xNode (aNode.get());
409 if (eErrCode != store_E_None)
411 if (eErrCode != store_E_AlreadyExists)
412 return eErrCode;
414 // Existing entry.
415 entry e (xNode->m_pData[i]);
416 if (e.m_aLink.location() != STORE_PAGE_NULL)
418 // Save page to existing location.
419 return saveObjectAt (rPage, e.m_aLink.location());
422 // Allocate page.
423 eErrCode = base::allocate (rPage);
424 if (eErrCode != store_E_None)
425 return eErrCode;
427 // Update page location.
428 xNode->m_pData[i].m_aLink = rPage.location();
430 // Save modified NodePage.
431 return saveObjectAt (aNode, aNode.location());
434 // Allocate page.
435 eErrCode = base::allocate (rPage);
436 if (eErrCode != store_E_None)
437 return eErrCode;
439 // Insert.
440 OStorePageLink aLink (rPage.location());
441 xNode->insert (i + 1, entry (rKey, aLink));
443 // Save modified NodePage.
444 return saveObjectAt (aNode, aNode.location());
448 * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)].
449 * Precond: initialized.
451 storeError OStorePageManager::attrib (
452 const OStorePageKey &rKey,
453 sal_uInt32 nMask1,
454 sal_uInt32 nMask2,
455 sal_uInt32 &rAttrib)
457 // Acquire exclusive access.
458 osl::MutexGuard aGuard(*this);
460 // Check precond.
461 if (!self::isValid())
462 return store_E_InvalidAccess;
464 // Find NodePage and index.
465 OStoreBTreeNodeObject aNode;
466 sal_uInt16 i = 0;
467 storeError eErrCode = find_lookup (aNode, i, rKey);
468 if (eErrCode != store_E_None)
469 return eErrCode;
471 // Existing entry.
472 PageHolderObject< page > xNode (aNode.get());
473 entry e (xNode->m_pData[i]);
474 if (nMask1 != nMask2)
476 // Evaluate new attributes.
477 sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib);
479 nAttrib &= ~nMask1;
480 nAttrib |= nMask2;
482 if (store::htonl(nAttrib) != e.m_nAttrib)
484 // Check access mode.
485 if (base::isWriteable())
487 // Set new attributes.
488 e.m_nAttrib = store::htonl(nAttrib);
489 xNode->m_pData[i] = e;
491 // Save modified NodePage.
492 eErrCode = saveObjectAt (aNode, aNode.location());
494 else
496 // Access denied.
497 eErrCode = store_E_AccessViolation;
502 // Obtain current attributes.
503 rAttrib = store::ntohl(e.m_nAttrib);
504 return eErrCode;
508 * link (insert 'Source' as hardlink to 'Destination').
509 * Precond: initialized, writeable.
511 storeError OStorePageManager::link (
512 const OStorePageKey &rSrcKey,
513 const OStorePageKey &rDstKey)
515 // Acquire exclusive access.
516 osl::MutexGuard aGuard(*this);
518 // Check precond.
519 if (!self::isValid())
520 return store_E_InvalidAccess;
522 if (!base::isWriteable())
523 return store_E_AccessViolation;
525 // Find 'Destination' NodePage and Index.
526 OStoreBTreeNodeObject aDstNode;
527 sal_uInt16 i = 0;
528 storeError eErrCode = find_lookup (aDstNode, i, rDstKey);
529 if (eErrCode != store_E_None)
530 return eErrCode;
532 // Existing 'Destination' entry.
533 PageHolderObject< page > xDstNode (aDstNode.get());
534 entry e (xDstNode->m_pData[i]);
535 OStorePageLink aDstLink (e.m_aLink);
537 // Find 'Source' NodePage and Index.
538 OStoreBTreeNodeObject aSrcNode;
539 eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this);
540 if (eErrCode != store_E_None)
541 return eErrCode;
543 // Insert 'Source' entry.
544 PageHolderObject< page > xSrcNode (aSrcNode.get());
545 xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK));
546 return saveObjectAt (aSrcNode, aSrcNode.location());
550 * symlink (insert 'Source' DirectoryPage as symlink to 'Destination').
551 * Precond: initialized, writeable.
553 storeError OStorePageManager::symlink (
554 const rtl_String *pSrcPath,
555 const rtl_String *pSrcName,
556 const OStorePageKey &rDstKey)
558 // Acquire exclusive access.
559 osl::MutexGuard aGuard(*this);
561 // Check precond.
562 if (!self::isValid())
563 return store_E_InvalidAccess;
565 if (!base::isWriteable())
566 return store_E_AccessViolation;
568 // Check 'Source' parameter.
569 storeError eErrCode = store_E_InvalidParameter;
570 if (!(pSrcPath && pSrcName))
571 return eErrCode;
573 // Setup 'Source' page key.
574 OStorePageKey aSrcKey;
575 eErrCode = namei (pSrcPath, pSrcName, aSrcKey);
576 if (eErrCode != store_E_None)
577 return eErrCode;
579 // Find 'Source' NodePage and Index.
580 OStoreBTreeNodeObject aSrcNode;
581 sal_uInt16 i = 0;
582 eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this);
583 if (eErrCode != store_E_None)
584 return eErrCode;
586 // Initialize directory page.
587 OStoreDirectoryPageObject aPage;
588 eErrCode = aPage.construct< inode >(base::allocator());
589 if (eErrCode != store_E_None)
590 return eErrCode;
592 // Setup as 'Source' directory page.
593 inode_holder_type xNode (aPage.get());
594 aPage.key (aSrcKey);
595 memcpy (
596 &(xNode->m_aNameBlock.m_pData[0]),
597 pSrcName->buffer, pSrcName->length);
599 // Store 'Destination' page key.
600 OStorePageKey aDstKey (rDstKey);
601 memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey));
603 // Mark 'Source' as symbolic link to 'Destination'.
604 aPage.attrib (STORE_ATTRIB_ISLINK);
605 aPage.dataLength (sal_uInt32(sizeof(aDstKey)));
607 // Allocate and save 'Source' directory page.
608 eErrCode = base::allocate (aPage);
609 if (eErrCode != store_E_None)
610 return eErrCode;
612 // Insert 'Source' entry.
613 PageHolderObject< page > xSrcNode (aSrcNode.get());
614 OStorePageLink aSrcLink (aPage.location());
615 xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink));
617 // Save modified NodePage.
618 return saveObjectAt (aSrcNode, aSrcNode.location());
622 * rename.
623 * Precond: initialized, writeable.
625 storeError OStorePageManager::rename (
626 const OStorePageKey &rSrcKey,
627 const rtl_String *pDstPath,
628 const rtl_String *pDstName)
630 // Acquire exclusive access.
631 osl::MutexGuard aGuard(*this);
633 // Check precond.
634 if (!self::isValid())
635 return store_E_InvalidAccess;
637 if (!base::isWriteable())
638 return store_E_AccessViolation;
640 // Check 'Destination' parameter.
641 storeError eErrCode = store_E_InvalidParameter;
642 if (!(pDstPath && pDstName))
643 return eErrCode;
645 // Setup 'Destination' page key.
646 OStorePageKey aDstKey;
647 eErrCode = namei (pDstPath, pDstName, aDstKey);
648 if (eErrCode != store_E_None)
649 return eErrCode;
651 // Find 'Source' NodePage and Index.
652 OStoreBTreeNodeObject aSrcNode;
653 sal_uInt16 i = 0;
654 eErrCode = find_lookup (aSrcNode, i, rSrcKey);
655 if (eErrCode != store_E_None)
656 return eErrCode;
658 // Existing 'Source' entry.
659 PageHolderObject< page > xSrcNode (aSrcNode.get());
660 entry e (xSrcNode->m_pData[i]);
662 // Check for (not a) hardlink.
663 OStoreDirectoryPageObject aPage;
664 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
666 // Load directory page.
667 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
668 if (eErrCode != store_E_None)
669 return eErrCode;
671 // Check for directory.
672 if (aPage.attrib() & STORE_ATTRIB_ISDIR)
674 // Ugly, but necessary (backward compatibility).
675 aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1));
679 // Let 'Source' entry be 'Destination' entry.
680 e.m_aKey = aDstKey;
682 // Find 'Destination' NodePage and Index.
683 OStoreBTreeNodeObject aDstNode;
684 eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this);
685 if (eErrCode != store_E_None)
686 return eErrCode;
688 // Insert 'Destination' entry.
689 PageHolderObject< page > xDstNode (aDstNode.get());
690 xDstNode->insert (i + 1, e);
692 eErrCode = saveObjectAt (aDstNode, aDstNode.location());
693 if (eErrCode != store_E_None)
694 return eErrCode;
696 // Check for (not a) hardlink.
697 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
699 // Modify 'Source' directory page.
700 inode_holder_type xNode (aPage.get());
702 // Setup 'Destination' NameBlock.
703 sal_Int32 nDstLen = pDstName->length;
704 memcpy (
705 &(xNode->m_aNameBlock.m_pData[0]),
706 pDstName->buffer, pDstName->length);
707 memset (
708 &(xNode->m_aNameBlock.m_pData[nDstLen]),
709 0, STORE_MAXIMUM_NAMESIZE - nDstLen);
710 aPage.key (e.m_aKey);
712 // Save directory page.
713 eErrCode = base::saveObjectAt (aPage, e.m_aLink.location());
714 if (eErrCode != store_E_None)
715 return eErrCode;
718 // Remove 'Source' entry.
719 e.m_aKey = rSrcKey;
720 return remove_Impl (e);
724 * remove.
725 * Precond: initialized, writeable.
727 storeError OStorePageManager::remove (const OStorePageKey &rKey)
729 // Acquire exclusive access.
730 osl::MutexGuard aGuard(*this);
732 // Check precond.
733 if (!self::isValid())
734 return store_E_InvalidAccess;
736 if (!base::isWriteable())
737 return store_E_AccessViolation;
739 // Find NodePage and index.
740 OStoreBTreeNodeObject aNodePage;
741 sal_uInt16 i = 0;
742 storeError eErrCode = find_lookup (aNodePage, i, rKey);
743 if (eErrCode != store_E_None)
744 return eErrCode;
746 // Existing entry.
747 PageHolderObject< page > xNodePage (aNodePage.get());
748 entry e (xNodePage->m_pData[i]);
750 // Check for (not a) hardlink.
751 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
753 // Load directory page.
754 OStoreDirectoryPageObject aPage;
755 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
756 if (eErrCode != store_E_None)
757 return eErrCode;
759 inode_holder_type xNode (aPage.get());
761 // Acquire page write access.
762 OStorePageDescriptor aDescr (xNode->m_aDescr);
763 eErrCode = base::acquirePage (aDescr, store_AccessReadWrite);
764 if (eErrCode != store_E_None)
765 return eErrCode;
767 // Check for symbolic link.
768 if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
770 // Ordinary inode. Determine 'Data' scope.
771 inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
772 if (eScope == inode::SCOPE_EXTERNAL)
774 // External 'Data' scope. Truncate all external data pages.
775 eErrCode = aPage.truncate (0, *this);
776 if (eErrCode != store_E_None)
777 return eErrCode;
780 // Truncate internal data page.
781 memset (&(xNode->m_pData[0]), 0, xNode->capacity());
782 aPage.dataLength (0);
785 // Release page write access.
786 eErrCode = base::releasePage (aDescr);
788 // Release and free directory page.
789 eErrCode = base::free (aPage.location());
792 // Remove entry.
793 return remove_Impl (e);
797 * RebuildContext.
799 struct RebuildContext
801 /** Representation.
803 rtl::Reference<OStorePageBIOS> m_xBIOS;
804 OStorePageBIOS::ScanContext m_aCtx;
805 sal_uInt16 m_nPageSize;
807 /** Construction.
809 RebuildContext (void)
810 : m_xBIOS (new OStorePageBIOS()),
811 m_nPageSize (0)
814 /** initialize (PageBIOS and ScanContext).
816 storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0)
818 storeError eErrCode = store_E_InvalidParameter;
819 if (pLockBytes)
821 m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize);
822 eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic);
824 return eErrCode;
827 /** initialize (ScanContext).
829 storeError initialize (sal_uInt32 nMagic = 0)
831 return m_xBIOS->scanBegin (m_aCtx, nMagic);
834 /** load (next ScanContext matching page).
836 storeError load (OStorePageObject &rPage)
838 if (m_aCtx.isValid())
839 return m_xBIOS->scanNext (m_aCtx, rPage);
840 else
841 return store_E_CantSeek;
846 * rebuild.
847 * Precond: none.
849 storeError OStorePageManager::rebuild (
850 ILockBytes *pSrcLB, ILockBytes *pDstLB)
852 // Acquire exclusive access.
853 osl::MutexGuard aGuard(*this);
855 // Check arguments.
856 storeError eErrCode = store_E_InvalidParameter;
857 if (!(pSrcLB && pDstLB))
858 return eErrCode;
860 // Initialize 'Source' rebuild context.
861 RebuildContext aCtx;
862 eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE);
863 if (eErrCode != store_E_None)
864 return eErrCode;
865 rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS);
867 // Initialize as 'Destination' with 'Source' page size.
868 eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize);
869 if (eErrCode != store_E_None)
870 return eErrCode;
872 // Pass One: Scan 'Source' directory pages.
874 // Scan 'Source' directory pages.
875 OStoreDirectoryPageObject aSrcPage;
876 while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None)
878 OStoreDirectoryPageObject aDstPage;
879 eErrCode = aDstPage.construct< inode >(base::allocator());
880 if (eErrCode != store_E_None)
881 break;
883 inode_holder_type xSrcDir (aSrcPage.get());
884 inode_holder_type xDstDir (aDstPage.get());
886 // Copy NameBlock @@@ OLD @@@
887 memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock));
889 // Obtain 'Source' data length.
890 sal_uInt32 nDataLen = aSrcPage.dataLength();
891 if (nDataLen > 0)
893 // Copy internal data area @@@ OLD @@@
894 memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity());
897 // Insert 'Destination' directory page.
898 eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage);
899 if (eErrCode != store_E_None)
900 break;
902 // Check for external data page scope.
903 if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL)
905 // Initialize 'Destination' data page.
906 typedef OStoreDataPageData data;
907 PageHolderObject< data > xData;
908 if (!xData.construct(base::allocator()))
909 return store_E_OutOfMemory;
911 // Determine data page count.
912 inode::ChunkDescriptor aDescr (
913 nDataLen - xDstDir->capacity(), xData->capacity());
915 sal_uInt32 i, n = aDescr.m_nPage;
916 if (aDescr.m_nOffset) n += 1;
918 // Copy data pages.
919 OStoreDataPageObject aData;
920 for (i = 0; i < n; i++)
922 // Read 'Source' data page.
923 osl::MutexGuard aSrcGuard (*xSrcBIOS);
925 eErrCode = aSrcPage.read (i, aData, *xSrcBIOS);
926 if (eErrCode != store_E_None)
927 continue;
929 // Write 'Destination' data page. @@@ READONLY @@@
930 eErrCode = aDstPage.write (i, aData, *this);
934 // Update 'Destination' directory page.
935 aDstPage.dataLength (nDataLen);
936 eErrCode = base::saveObjectAt (aDstPage, aDstPage.location());
939 // Save directory scan results.
940 flush();
943 // Pass Two: Scan 'Source' BTree nodes.
945 // Re-start 'Source' rebuild context.
946 aCtx.initialize (STORE_MAGIC_BTREENODE);
948 // Scan 'Source' BTree nodes.
949 OStoreBTreeNodeObject aNode;
950 while ((eErrCode = aCtx.load(aNode)) == store_E_None)
952 // Check for leaf node.
953 PageHolderObject< page > xNode (aNode.get());
954 if (xNode->depth() == 0)
956 sal_uInt16 i, n = xNode->usageCount();
957 for (i = 0; i < n; i++)
959 entry e (xNode->m_pData[i]);
961 // Check for Hard link.
962 if (e.m_nAttrib & STORE_ATTRIB_ISLINK)
964 // Load the hard link destination.
965 OStoreDirectoryPageObject aSrcPage;
966 eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location());
967 if (eErrCode == store_E_None)
969 OStorePageKey aDstKey (aSrcPage.key());
970 eErrCode = link (e.m_aKey, aDstKey);
972 e.m_nAttrib &= ~STORE_ATTRIB_ISLINK;
975 if (e.m_nAttrib)
977 // Ordinary attributes.
978 sal_uInt32 nAttrib = 0;
979 eErrCode = attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib);
985 // Save BTree node scan results.
986 flush();
989 // Done.
990 return store_E_None;
993 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */