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