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