xref: /AOO41X/main/store/source/storpage.cxx (revision 73d9b18ad12b526a229c2c5ca3fb0f85a41c2f42)
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