merge the formfield patch from ooo-build
[ooovba.git] / store / source / storpage.cxx
bloba7c59be871980b095ac4dfe5b5dbcc73d6479730
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: storpage.cxx,v $
10 * $Revision: 1.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_store.hxx"
34 #include "storpage.hxx"
36 #include "sal/types.h"
37 #include "rtl/string.h"
38 #include "rtl/ref.hxx"
39 #include "osl/diagnose.h"
40 #include "osl/mutex.hxx"
42 #include "store/types.h"
44 #include "object.hxx"
45 #include "lockbyte.hxx"
47 #include "storbase.hxx"
48 #include "stordata.hxx"
49 #include "stortree.hxx"
51 using namespace store;
53 /*========================================================================
55 * OStorePageManager implementation.
57 *======================================================================*/
58 const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
61 * OStorePageManager.
63 OStorePageManager::OStorePageManager (void)
68 * ~OStorePageManager.
70 OStorePageManager::~OStorePageManager (void)
75 * isKindOf.
77 sal_Bool SAL_CALL OStorePageManager::isKindOf (sal_uInt32 nTypeId)
79 return (nTypeId == m_nTypeId);
83 * initialize (two-phase construction).
84 * Precond: none.
86 storeError OStorePageManager::initialize (
87 ILockBytes * pLockBytes,
88 storeAccessMode eAccessMode,
89 sal_uInt16 & rnPageSize)
91 // Acquire exclusive access.
92 osl::MutexGuard aGuard(*this);
94 // Check arguments.
95 if (!pLockBytes)
96 return store_E_InvalidParameter;
98 // Initialize base.
99 storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
100 if (eErrCode != store_E_None)
101 return eErrCode;
103 // Check for (not) writeable.
104 if (!base::isWriteable())
106 // Readonly. Load RootNode.
107 return base::loadObjectAt (m_aRoot, rnPageSize);
110 // Writeable. Load or Create RootNode.
111 eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
112 if (eErrCode == store_E_Pending)
114 // Creation notification.
115 PageHolderObject< page > xRoot (m_aRoot.get());
117 // Pre-allocate left most entry (ugly, but we can't insert to left).
118 OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
119 xRoot->insert (0, entry(aKey));
121 // Save RootNode.
122 eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
123 if (eErrCode != store_E_None)
124 return eErrCode;
126 // Flush for robustness.
127 (void) base::flush();
130 // Done.
131 return eErrCode;
135 * find_lookup (w/o split()).
136 * Internal: Precond: initialized, readable, exclusive access.
138 storeError OStorePageManager::find_lookup (
139 OStoreBTreeNodeObject & rNode,
140 sal_uInt16 & rIndex,
141 OStorePageKey const & rKey)
143 // Find Node and Index.
144 storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
145 if (eErrCode != store_E_None)
146 return eErrCode;
148 // Greater or Equal.
149 PageHolderObject< page > xPage (rNode.get());
150 OSL_POSTCOND(rIndex < xPage->usageCount(), "store::PageManager::find_lookup(): logic error");
151 entry e (xPage->m_pData[rIndex]);
153 // Check for exact match.
154 if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
156 // Page not present.
157 return store_E_NotExists;
160 // Check address.
161 if (e.m_aLink.location() == STORE_PAGE_NULL)
163 // Page not present.
164 return store_E_NotExists;
167 return store_E_None;
171 * remove_Impl (possibly down from root).
172 * Internal: Precond: initialized, writeable, exclusive access.
174 #if 0 /* EXP */
175 storeError OStorePageManager::remove_Impl (entry & rEntry)
177 // Find Node and Index.
178 OStoreBTreeNodeObject aNode;
179 sal_uInt16 nIndex = 0;
180 eErrCode = m_aRoot.find_lookup (aNode, nIndex, entry::CompareGreater(rEntry), *this);
182 // @@@
184 PageHolderObject< page > xPage (aNode.get());
185 page & rPage = (*xPage);
187 // Check current page index.
188 sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount();
189 if (!(i < n))
191 // Path to entry not exists (Must not happen(?)).
192 return store_E_NotExists;
195 // Compare entry.
196 entry::CompareResult result = rEntry.compare (rPage.m_pData[i]);
198 for (; result == entry::COMPARE_GREATER && xPage->depth() > 0; )
200 // Check next node address.
201 sal_uInt32 const nAddr = rPage.m_pData[i].m_aLink.location();
202 if (nAddr == STORE_PAGE_NULL)
204 // Path to entry not exists (Must not happen(?)).
205 return store_E_NotExists;
208 // Load next node page.
209 eErrCode = loadObjectAt (aNode, nAddr);
211 PageHolderObject< page > xNext (aNode.get());
212 xNext.swap (xPage);
215 aNode.remove (nIndex, rEntry, *this);
220 // Load next node page.
221 eErrCode = loadObjectAt (aNode, nAddr);
223 page const & rPage = (*xPage);
225 // Check current page index.
226 sal_uInt16 i = rPage.find (rEntry), n = rPage.usageCount();
227 if (!(i < n))
229 // Path to entry not exists (Must not happen(?)).
230 return store_E_NotExists;
233 // Compare entry.
234 result = rEntry.compare (rPage.m_pData[i]);
236 } while (result == entry::COMPATE_GREATER);
238 #endif /* EXP */
240 storeError OStorePageManager::remove_Impl (entry & rEntry)
242 OStoreBTreeNodeObject aNode (m_aRoot.get());
244 // Check current page index.
245 PageHolderObject< page > xPage (aNode.get());
246 sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
247 if (!(i < n))
249 // Path to entry not exists (Must not happen(?)).
250 return store_E_NotExists;
253 // Compare entry.
254 entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
256 // Iterate down until equal match.
257 while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
259 // Check link address.
260 sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
261 if (nAddr == STORE_PAGE_NULL)
263 // Path to entry not exists (Must not happen(?)).
264 return store_E_NotExists;
267 // Load link page.
268 storeError eErrCode = loadObjectAt (aNode, nAddr);
269 if (eErrCode != store_E_None)
270 return eErrCode;
272 PageHolderObject< page > xNext (aNode.get());
273 xNext.swap (xPage);
275 // Check index.
276 i = xPage->find (rEntry), n = xPage->usageCount();
277 if (!(i < n))
279 // Path to entry not exists (Must not happen(?)).
280 return store_E_NotExists;
283 // Compare entry.
284 result = rEntry.compare (xPage->m_pData[i]);
287 OSL_POSTCOND(
288 result != entry::COMPARE_LESS,
289 "OStorePageManager::remove(): find failed");
291 // Check entry comparison.
292 if (result == entry::COMPARE_LESS)
294 // Must not happen.
295 return store_E_Unknown;
298 // Remove down from current page (recursive).
299 return aNode.remove (i, rEntry, *this);
303 * namei.
304 * Precond: none (static).
306 storeError OStorePageManager::namei (
307 const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
309 // Check parameter.
310 if (!(pPath && pName))
311 return store_E_InvalidParameter;
313 // Check name length.
314 if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
315 return store_E_NameTooLong;
317 // Transform pathname into key.
318 rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
319 rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
321 // Done.
322 return store_E_None;
326 * iget.
327 * Precond: initialized.
329 storeError OStorePageManager::iget (
330 OStoreDirectoryPageObject & rPage,
331 sal_uInt32 nAttrib,
332 const rtl_String * pPath,
333 const rtl_String * pName,
334 storeAccessMode eMode)
336 // Acquire exclusive access.
337 osl::MutexGuard aGuard(*this);
339 // Check precond.
340 if (!self::isValid())
341 return store_E_InvalidAccess;
343 // Setup inode page key.
344 OStorePageKey aKey;
345 storeError eErrCode = namei (pPath, pName, aKey);
346 if (eErrCode != store_E_None)
347 return eErrCode;
349 // Check for directory.
350 if (nAttrib & STORE_ATTRIB_ISDIR)
352 // Ugly, but necessary (backward compatibility).
353 aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
356 // Load inode page.
357 eErrCode = load_dirpage_Impl (aKey, rPage);
358 if (eErrCode != store_E_None)
360 // Check mode and reason.
361 if (eErrCode != store_E_NotExists)
362 return eErrCode;
364 if (eMode == store_AccessReadWrite)
365 return store_E_NotExists;
366 if (eMode == store_AccessReadOnly)
367 return store_E_NotExists;
369 if (!base::isWriteable())
370 return store_E_AccessViolation;
372 // Create inode page.
373 eErrCode = rPage.construct< inode >(base::allocator());
374 if (eErrCode != store_E_None)
375 return eErrCode;
377 // Setup inode nameblock.
378 PageHolderObject< inode > xPage (rPage.get());
380 rPage.key (aKey);
381 rPage.attrib (nAttrib);
383 memcpy (
384 &(xPage->m_aNameBlock.m_pData[0]),
385 pName->buffer, pName->length);
387 // Save inode page.
388 eErrCode = save_dirpage_Impl (aKey, rPage);
389 if (eErrCode != store_E_None)
390 return eErrCode;
393 // Check for symbolic link.
394 if (rPage.attrib() & STORE_ATTRIB_ISLINK)
396 // Obtain 'Destination' page key.
397 PageHolderObject< inode > xPage (rPage.get());
398 OStorePageKey aDstKey;
399 memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
401 // Load 'Destination' inode.
402 eErrCode = load_dirpage_Impl (aDstKey, rPage);
403 if (eErrCode != store_E_None)
404 return eErrCode;
407 // Done.
408 return store_E_None;
412 * iterate.
413 * Precond: initialized.
414 * ToDo: skip hardlink entries.
416 storeError OStorePageManager::iterate (
417 OStorePageKey & rKey,
418 OStorePageLink & rLink,
419 sal_uInt32 & rAttrib)
421 // Acquire exclusive access.
422 osl::MutexGuard aGuard(*this);
424 // Check precond.
425 if (!self::isValid())
426 return store_E_InvalidAccess;
428 // Find NodePage and Index.
429 OStoreBTreeNodeObject aNode;
430 sal_uInt16 i = 0;
431 storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
432 if (eErrCode != store_E_None)
433 return eErrCode;
435 // GreaterEqual. Found next entry.
436 PageHolderObject< page > xNode (aNode.get());
437 entry e (xNode->m_pData[i]);
439 // Setup result.
440 rKey = e.m_aKey;
441 rLink = e.m_aLink;
442 rAttrib = store::ntohl(e.m_nAttrib);
444 // Done.
445 return store_E_None;
449 * load => private: iget() @@@
450 * Internal: Precond: initialized, exclusive access.
452 storeError OStorePageManager::load_dirpage_Impl (
453 const OStorePageKey &rKey,
454 OStoreDirectoryPageObject &rPage)
456 // Find Node 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. Load page.
464 PageHolderObject< page > xNode (aNode.get());
465 entry e (xNode->m_pData[i]);
466 return loadObjectAt (rPage, e.m_aLink.location());
470 * save => private: iget(), rebuild() @@@
471 * Internal: Precond: initialized, writeable, exclusive access.
473 storeError OStorePageManager::save_dirpage_Impl (
474 const OStorePageKey &rKey,
475 OStoreDirectoryPageObject &rPage)
477 // Find NodePage and Index.
478 node aNode;
479 sal_uInt16 i = 0;
481 storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
482 PageHolderObject< page > xNode (aNode.get());
483 if (eErrCode != store_E_None)
485 if (eErrCode != store_E_AlreadyExists)
486 return eErrCode;
488 // Existing entry.
489 entry e (xNode->m_pData[i]);
490 if (e.m_aLink.location() != STORE_PAGE_NULL)
492 // Save page to existing location.
493 return saveObjectAt (rPage, e.m_aLink.location());
496 // Allocate page.
497 eErrCode = base::allocate (rPage);
498 if (eErrCode != store_E_None)
499 return eErrCode;
501 // Update page location.
502 xNode->m_pData[i].m_aLink = rPage.location();
504 // Save modified NodePage.
505 return saveObjectAt (aNode, aNode.location());
508 // Allocate page.
509 eErrCode = base::allocate (rPage);
510 if (eErrCode != store_E_None)
511 return eErrCode;
513 // Insert.
514 OStorePageLink aLink (rPage.location());
515 xNode->insert (i + 1, entry (rKey, aLink));
517 // Save modified NodePage.
518 return saveObjectAt (aNode, aNode.location());
522 * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)].
523 * Precond: initialized.
525 storeError OStorePageManager::attrib (
526 const OStorePageKey &rKey,
527 sal_uInt32 nMask1,
528 sal_uInt32 nMask2,
529 sal_uInt32 &rAttrib)
531 // Acquire exclusive access.
532 osl::MutexGuard aGuard(*this);
534 // Check precond.
535 if (!self::isValid())
536 return store_E_InvalidAccess;
538 // Find NodePage and index.
539 OStoreBTreeNodeObject aNode;
540 sal_uInt16 i = 0;
541 storeError eErrCode = find_lookup (aNode, i, rKey);
542 if (eErrCode != store_E_None)
543 return eErrCode;
545 // Existing entry.
546 PageHolderObject< page > xNode (aNode.get());
547 entry e (xNode->m_pData[i]);
548 if (nMask1 != nMask2)
550 // Evaluate new attributes.
551 sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib);
553 nAttrib &= ~nMask1;
554 nAttrib |= nMask2;
556 if (store::htonl(nAttrib) != e.m_nAttrib)
558 // Check access mode.
559 if (base::isWriteable())
561 // Set new attributes.
562 e.m_nAttrib = store::htonl(nAttrib);
563 xNode->m_pData[i] = e;
565 // Save modified NodePage.
566 eErrCode = saveObjectAt (aNode, aNode.location());
568 else
570 // Access denied.
571 eErrCode = store_E_AccessViolation;
576 // Obtain current attributes.
577 rAttrib = store::ntohl(e.m_nAttrib);
578 return eErrCode;
582 * link (insert 'Source' as hardlink to 'Destination').
583 * Precond: initialized, writeable.
585 storeError OStorePageManager::link (
586 const OStorePageKey &rSrcKey,
587 const OStorePageKey &rDstKey)
589 // Acquire exclusive access.
590 osl::MutexGuard aGuard(*this);
592 // Check precond.
593 if (!self::isValid())
594 return store_E_InvalidAccess;
596 if (!base::isWriteable())
597 return store_E_AccessViolation;
599 // Find 'Destination' NodePage and Index.
600 OStoreBTreeNodeObject aDstNode;
601 sal_uInt16 i = 0;
602 storeError eErrCode = find_lookup (aDstNode, i, rDstKey);
603 if (eErrCode != store_E_None)
604 return eErrCode;
606 // Existing 'Destination' entry.
607 PageHolderObject< page > xDstNode (aDstNode.get());
608 entry e (xDstNode->m_pData[i]);
609 OStorePageLink aDstLink (e.m_aLink);
611 // Find 'Source' NodePage and Index.
612 OStoreBTreeNodeObject aSrcNode;
613 eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this);
614 if (eErrCode != store_E_None)
615 return eErrCode;
617 // Insert 'Source' entry.
618 PageHolderObject< page > xSrcNode (aSrcNode.get());
619 xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK));
620 return saveObjectAt (aSrcNode, aSrcNode.location());
624 * symlink (insert 'Source' DirectoryPage as symlink to 'Destination').
625 * Precond: initialized, writeable.
627 storeError OStorePageManager::symlink (
628 const rtl_String *pSrcPath,
629 const rtl_String *pSrcName,
630 const OStorePageKey &rDstKey)
632 // Acquire exclusive access.
633 osl::MutexGuard aGuard(*this);
635 // Check precond.
636 if (!self::isValid())
637 return store_E_InvalidAccess;
639 if (!base::isWriteable())
640 return store_E_AccessViolation;
642 // Check 'Source' parameter.
643 storeError eErrCode = store_E_InvalidParameter;
644 if (!(pSrcPath && pSrcName))
645 return eErrCode;
647 // Setup 'Source' page key.
648 OStorePageKey aSrcKey;
649 eErrCode = namei (pSrcPath, pSrcName, aSrcKey);
650 if (eErrCode != store_E_None)
651 return eErrCode;
653 // Find 'Source' NodePage and Index.
654 OStoreBTreeNodeObject aSrcNode;
655 sal_uInt16 i = 0;
656 eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this);
657 if (eErrCode != store_E_None)
658 return eErrCode;
660 // Initialize directory page.
661 OStoreDirectoryPageObject aPage;
662 eErrCode = aPage.construct< inode >(base::allocator());
663 if (eErrCode != store_E_None)
664 return eErrCode;
666 // Setup as 'Source' directory page.
667 inode_holder_type xNode (aPage.get());
668 aPage.key (aSrcKey);
669 memcpy (
670 &(xNode->m_aNameBlock.m_pData[0]),
671 pSrcName->buffer, pSrcName->length);
673 // Store 'Destination' page key.
674 OStorePageKey aDstKey (rDstKey);
675 memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey));
677 // Mark 'Source' as symbolic link to 'Destination'.
678 aPage.attrib (STORE_ATTRIB_ISLINK);
679 aPage.dataLength (sal_uInt32(sizeof(aDstKey)));
681 // Allocate and save 'Source' directory page.
682 eErrCode = base::allocate (aPage);
683 if (eErrCode != store_E_None)
684 return eErrCode;
686 // Insert 'Source' entry.
687 PageHolderObject< page > xSrcNode (aSrcNode.get());
688 OStorePageLink aSrcLink (aPage.location());
689 xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink));
691 // Save modified NodePage.
692 return saveObjectAt (aSrcNode, aSrcNode.location());
696 * rename.
697 * Precond: initialized, writeable.
699 storeError OStorePageManager::rename (
700 const OStorePageKey &rSrcKey,
701 const rtl_String *pDstPath,
702 const rtl_String *pDstName)
704 // Acquire exclusive access.
705 osl::MutexGuard aGuard(*this);
707 // Check precond.
708 if (!self::isValid())
709 return store_E_InvalidAccess;
711 if (!base::isWriteable())
712 return store_E_AccessViolation;
714 // Check 'Destination' parameter.
715 storeError eErrCode = store_E_InvalidParameter;
716 if (!(pDstPath && pDstName))
717 return eErrCode;
719 // Setup 'Destination' page key.
720 OStorePageKey aDstKey;
721 eErrCode = namei (pDstPath, pDstName, aDstKey);
722 if (eErrCode != store_E_None)
723 return eErrCode;
725 // Find 'Source' NodePage and Index.
726 OStoreBTreeNodeObject aSrcNode;
727 sal_uInt16 i = 0;
728 eErrCode = find_lookup (aSrcNode, i, rSrcKey);
729 if (eErrCode != store_E_None)
730 return eErrCode;
732 // Existing 'Source' entry.
733 PageHolderObject< page > xSrcNode (aSrcNode.get());
734 entry e (xSrcNode->m_pData[i]);
736 // Check for (not a) hardlink.
737 OStoreDirectoryPageObject aPage;
738 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
740 // Load directory page.
741 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
742 if (eErrCode != store_E_None)
743 return eErrCode;
745 // Check for directory.
746 if (aPage.attrib() & STORE_ATTRIB_ISDIR)
748 // Ugly, but necessary (backward compatibility).
749 aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1));
753 // Let 'Source' entry be 'Destination' entry.
754 e.m_aKey = aDstKey;
756 // Find 'Destination' NodePage and Index.
757 OStoreBTreeNodeObject aDstNode;
758 eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this);
759 if (eErrCode != store_E_None)
760 return eErrCode;
762 // Insert 'Destination' entry.
763 PageHolderObject< page > xDstNode (aDstNode.get());
764 xDstNode->insert (i + 1, e);
766 eErrCode = saveObjectAt (aDstNode, aDstNode.location());
767 if (eErrCode != store_E_None)
768 return eErrCode;
770 // Check for (not a) hardlink.
771 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
773 // Modify 'Source' directory page.
774 inode_holder_type xNode (aPage.get());
776 // Setup 'Destination' NameBlock.
777 sal_Int32 nDstLen = pDstName->length;
778 memcpy (
779 &(xNode->m_aNameBlock.m_pData[0]),
780 pDstName->buffer, pDstName->length);
781 memset (
782 &(xNode->m_aNameBlock.m_pData[nDstLen]),
783 0, STORE_MAXIMUM_NAMESIZE - nDstLen);
784 aPage.key (e.m_aKey);
786 // Save directory page.
787 eErrCode = base::saveObjectAt (aPage, e.m_aLink.location());
788 if (eErrCode != store_E_None)
789 return eErrCode;
792 // Remove 'Source' entry.
793 e.m_aKey = rSrcKey;
794 return remove_Impl (e);
798 * remove.
799 * Precond: initialized, writeable.
801 storeError OStorePageManager::remove (const OStorePageKey &rKey)
803 // Acquire exclusive access.
804 osl::MutexGuard aGuard(*this);
806 // Check precond.
807 if (!self::isValid())
808 return store_E_InvalidAccess;
810 if (!base::isWriteable())
811 return store_E_AccessViolation;
813 // Find NodePage and index.
814 OStoreBTreeNodeObject aNodePage;
815 sal_uInt16 i = 0;
816 storeError eErrCode = find_lookup (aNodePage, i, rKey);
817 if (eErrCode != store_E_None)
818 return eErrCode;
820 // Existing entry.
821 PageHolderObject< page > xNodePage (aNodePage.get());
822 entry e (xNodePage->m_pData[i]);
824 // Check for (not a) hardlink.
825 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
827 // Load directory page.
828 OStoreDirectoryPageObject aPage;
829 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
830 if (eErrCode != store_E_None)
831 return eErrCode;
833 inode_holder_type xNode (aPage.get());
835 // Acquire page write access.
836 OStorePageDescriptor aDescr (xNode->m_aDescr);
837 eErrCode = base::acquirePage (aDescr, store_AccessReadWrite);
838 if (eErrCode != store_E_None)
839 return eErrCode;
841 // Check for symbolic link.
842 if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
844 // Ordinary inode. Determine 'Data' scope.
845 inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
846 if (eScope == inode::SCOPE_EXTERNAL)
848 // External 'Data' scope. Truncate all external data pages.
849 eErrCode = aPage.truncate (0, *this);
850 if (eErrCode != store_E_None)
851 return eErrCode;
854 // Truncate internal data page.
855 memset (&(xNode->m_pData[0]), 0, xNode->capacity());
856 aPage.dataLength (0);
859 // Release page write access.
860 eErrCode = base::releasePage (aDescr, store_AccessReadWrite);
862 // Release and free directory page.
863 OStorePageData aPageHead;
864 eErrCode = base::free (aPageHead, aPage.location());
867 // Remove entry.
868 return remove_Impl (e);
872 * RebuildContext.
874 struct RebuildContext
876 /** Representation.
878 rtl::Reference<OStorePageBIOS> m_xBIOS;
879 OStorePageBIOS::ScanContext m_aCtx;
880 sal_uInt16 m_nPageSize;
882 /** Construction.
884 RebuildContext (void)
885 : m_xBIOS (new OStorePageBIOS()),
886 m_nPageSize (0)
889 /** initialize (PageBIOS and ScanContext).
891 storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0)
893 storeError eErrCode = store_E_InvalidParameter;
894 if (pLockBytes)
896 m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize);
897 eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic);
899 return eErrCode;
902 /** initialize (ScanContext).
904 storeError initialize (sal_uInt32 nMagic = 0)
906 return m_xBIOS->scanBegin (m_aCtx, nMagic);
909 /** load (next ScanContext matching page).
911 storeError load (OStorePageObject &rPage)
913 if (m_aCtx.isValid())
914 return m_xBIOS->scanNext (m_aCtx, rPage);
915 else
916 return store_E_CantSeek;
921 * rebuild.
922 * Precond: none.
924 storeError OStorePageManager::rebuild (
925 ILockBytes *pSrcLB, ILockBytes *pDstLB)
927 // Acquire exclusive access.
928 osl::MutexGuard aGuard(*this);
930 // Check arguments.
931 storeError eErrCode = store_E_InvalidParameter;
932 if (!(pSrcLB && pDstLB))
933 return eErrCode;
935 // Initialize 'Source' rebuild context.
936 RebuildContext aCtx;
937 eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE);
938 if (eErrCode != store_E_None)
939 return eErrCode;
940 rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS);
942 // Initialize as 'Destination' with 'Source' page size.
943 eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize);
944 if (eErrCode != store_E_None)
945 return eErrCode;
947 // Pass One: Scan 'Source' directory pages.
949 // Scan 'Source' directory pages.
950 OStoreDirectoryPageObject aSrcPage;
951 while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None)
953 OStoreDirectoryPageObject aDstPage;
954 eErrCode = aDstPage.construct< inode >(base::allocator());
955 if (eErrCode != store_E_None)
956 break;
958 inode_holder_type xSrcDir (aSrcPage.get());
959 inode_holder_type xDstDir (aDstPage.get());
961 // Copy NameBlock @@@ OLD @@@
962 memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock));
964 // Obtain 'Source' data length.
965 sal_uInt32 nDataLen = aSrcPage.dataLength();
966 if (nDataLen > 0)
968 // Copy internal data area @@@ OLD @@@
969 memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity());
972 // Insert 'Destination' directory page.
973 eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage);
974 if (eErrCode != store_E_None)
975 break;
977 // Check for external data page scope.
978 if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL)
980 // Initialize 'Destination' data page.
981 typedef OStoreDataPageData data;
982 PageHolderObject< data > xData;
983 if (!xData.construct(base::allocator()))
984 return store_E_OutOfMemory;
986 // Determine data page count.
987 inode::ChunkDescriptor aDescr (
988 nDataLen - xDstDir->capacity(), xData->capacity());
990 sal_uInt32 i, n = aDescr.m_nPage;
991 if (aDescr.m_nOffset) n += 1;
993 // Copy data pages.
994 OStoreDataPageObject aData;
995 for (i = 0; i < n; i++)
997 // Read 'Source' data page.
998 osl::MutexGuard aSrcGuard (*xSrcBIOS);
1000 eErrCode = aSrcPage.read (i, aData, *xSrcBIOS);
1001 if (eErrCode != store_E_None)
1002 continue;
1004 // Write 'Destination' data page. @@@ READONLY @@@
1005 eErrCode = aDstPage.write (i, aData, *this);
1009 // Update 'Destination' directory page.
1010 aDstPage.dataLength (nDataLen);
1011 eErrCode = base::saveObjectAt (aDstPage, aDstPage.location());
1014 // Save directory scan results.
1015 flush();
1018 // Pass Two: Scan 'Source' BTree nodes.
1020 // Re-start 'Source' rebuild context.
1021 aCtx.initialize (STORE_MAGIC_BTREENODE);
1023 // Scan 'Source' BTree nodes.
1024 OStoreBTreeNodeObject aNode;
1025 while ((eErrCode = aCtx.load(aNode)) == store_E_None)
1027 // Check for leaf node.
1028 PageHolderObject< page > xNode (aNode.get());
1029 if (xNode->depth() == 0)
1031 sal_uInt16 i, n = xNode->usageCount();
1032 for (i = 0; i < n; i++)
1034 entry e (xNode->m_pData[i]);
1036 // Check for Hard link.
1037 if (e.m_nAttrib & STORE_ATTRIB_ISLINK)
1039 // Load the hard link destination.
1040 OStoreDirectoryPageObject aSrcPage;
1041 eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location());
1042 if (eErrCode == store_E_None)
1044 OStorePageKey aDstKey (aSrcPage.key());
1045 eErrCode = link (e.m_aKey, aDstKey);
1047 e.m_nAttrib &= ~STORE_ATTRIB_ISLINK;
1050 if (e.m_nAttrib)
1052 // Ordinary attributes.
1053 sal_uInt32 nAttrib = 0;
1054 eErrCode = attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib);
1060 // Save BTree node scan results.
1061 flush();
1064 // Done.
1065 return store_E_None;