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 */ 56 OStorePageManager::OStorePageManager (void) 57 { 58 } 59 60 /* 61 * ~OStorePageManager. 62 */ 63 OStorePageManager::~OStorePageManager (void) 64 { 65 } 66 67 /* 68 * isKindOf. 69 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 871 RebuildContext (void) 872 : m_xBIOS (new OStorePageBIOS()), 873 m_nPageSize (0) 874 {} 875 876 /** initialize (PageBIOS and ScanContext). 877 */ 878 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 */ 891 storeError initialize (sal_uInt32 nMagic = 0) 892 { 893 return m_xBIOS->scanBegin (m_aCtx, nMagic); 894 } 895 896 /** load (next ScanContext matching page). 897 */ 898 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 */ 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