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