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