Bug Summary

File:store/source/storpage.cxx
Location:line 163, column 20
Description:Called C++ object pointer is null

Annotated Source Code

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