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 "storbios.hxx" 32 33 #include "sal/types.h" 34 #include "sal/macros.h" 35 36 #include "rtl/alloc.h" 37 #include "rtl/ref.hxx" 38 39 #include "osl/diagnose.h" 40 #include "osl/mutex.hxx" 41 42 #include "store/types.h" 43 #include "object.hxx" 44 #include "lockbyte.hxx" 45 #include "storcach.hxx" 46 47 using namespace store; 48 49 /*======================================================================== 50 * 51 * OStoreSuperBlock. 52 * 53 *======================================================================*/ 54 #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343) 55 56 struct OStoreSuperBlock 57 { 58 typedef OStorePageGuard G; 59 typedef OStorePageDescriptor D; 60 typedef OStorePageLink L; 61 62 /** Representation. 63 */ 64 G m_aGuard; 65 D m_aDescr; 66 sal_uInt32 m_nMarked; 67 L m_aMarked; 68 sal_uInt32 m_nUnused; 69 L m_aUnused; 70 71 /** theSize. 72 */ 73 static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32)); 74 75 /** Construction. 76 */ 77 explicit OStoreSuperBlock (sal_uInt16 nPageSize) 78 : m_aGuard (STORE_MAGIC_SUPERBLOCK), 79 m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE), 80 m_nMarked (store::htonl(0)), 81 m_aMarked (0), 82 m_nUnused (store::htonl(0)), 83 m_aUnused (0) 84 {} 85 86 OStoreSuperBlock (const OStoreSuperBlock & rhs) 87 : m_aGuard (rhs.m_aGuard), 88 m_aDescr (rhs.m_aDescr), 89 m_nMarked (rhs.m_nMarked), 90 m_aMarked (rhs.m_aMarked), 91 m_nUnused (rhs.m_nUnused), 92 m_aUnused (rhs.m_aUnused) 93 {} 94 95 OStoreSuperBlock& operator= (const OStoreSuperBlock & rhs) 96 { 97 m_aGuard = rhs.m_aGuard; 98 m_aDescr = rhs.m_aDescr; 99 m_nMarked = rhs.m_nMarked; 100 m_aMarked = rhs.m_aMarked; 101 m_nUnused = rhs.m_nUnused; 102 m_aUnused = rhs.m_aUnused; 103 return *this; 104 } 105 106 /** Comparison. 107 */ 108 sal_Bool operator== (const OStoreSuperBlock & rhs) const 109 { 110 return ((m_aGuard == rhs.m_aGuard ) && 111 (m_aDescr == rhs.m_aDescr ) && 112 (m_nMarked == rhs.m_nMarked) && 113 (m_aMarked == rhs.m_aMarked) && 114 (m_nUnused == rhs.m_nUnused) && 115 (m_aUnused == rhs.m_aUnused) ); 116 } 117 118 /** unused(Count|Head|Insert|Remove|Reset). 119 */ 120 sal_uInt32 unusedCount (void) const 121 { 122 return store::ntohl(m_nUnused); 123 } 124 const L& unusedHead (void) const 125 { 126 return m_aUnused; 127 } 128 void unusedInsert (const L& rLink) 129 { 130 sal_uInt32 nUnused = unusedCount(); 131 m_nUnused = store::htonl(nUnused + 1); 132 m_aUnused = rLink; 133 } 134 void unusedRemove (const L& rLink) 135 { 136 sal_uInt32 nUnused = unusedCount(); 137 m_nUnused = store::htonl(nUnused - 1); 138 m_aUnused = rLink; 139 } 140 void unusedReset (void) 141 { 142 m_nUnused = store::htonl(0); 143 m_aUnused = L(0); 144 } 145 146 /** guard (external representation). 147 */ 148 void guard() 149 { 150 sal_uInt32 nCRC32 = 0; 151 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); 152 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); 153 m_aGuard.m_nCRC32 = store::htonl(nCRC32); 154 } 155 156 /** verify (external representation). 157 */ 158 storeError verify() const 159 { 160 sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic); 161 if (nMagic != STORE_MAGIC_SUPERBLOCK) 162 return store_E_WrongFormat; 163 164 sal_uInt32 nCRC32 = 0; 165 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32)); 166 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G)); 167 if (m_aGuard.m_nCRC32 != store::htonl(nCRC32)) 168 return store_E_InvalidChecksum; 169 else 170 return store_E_None; 171 } 172 }; 173 174 /*======================================================================== 175 * 176 * SuperBlockPage interface. 177 * 178 *======================================================================*/ 179 namespace store 180 { 181 182 struct SuperBlockPage 183 { 184 typedef OStoreSuperBlock SuperBlock; 185 186 /** Representation. 187 */ 188 SuperBlock m_aSuperOne; 189 SuperBlock m_aSuperTwo; 190 191 /** theSize. 192 */ 193 static const size_t theSize = 2 * SuperBlock::theSize; 194 static const sal_uInt16 thePageSize = theSize; 195 STORE_STATIC_ASSERT(STORE_MINIMUM_PAGESIZE >= thePageSize); 196 197 /** Allocation. 198 */ 199 static void * operator new (size_t n) SAL_THROW(()) 200 { 201 return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n)); 202 } 203 static void operator delete (void * p, size_t) SAL_THROW(()) 204 { 205 rtl_freeMemory (p); 206 } 207 208 static void * operator new (size_t, sal_uInt16 nPageSize) SAL_THROW(()) 209 { 210 return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize)); 211 } 212 static void operator delete (void * p, sal_uInt16) SAL_THROW(()) 213 { 214 rtl_freeMemory (p); 215 } 216 217 /** Construction. 218 */ 219 explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize) 220 : m_aSuperOne(nPageSize), 221 m_aSuperTwo(nPageSize) 222 {} 223 224 /** save. 225 */ 226 storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize) 227 { 228 m_aSuperOne.guard(); 229 m_aSuperTwo = m_aSuperOne; 230 return rBIOS.write (0, this, nSize); 231 } 232 233 /** Page allocation. 234 */ 235 storeError unusedHead ( 236 OStorePageBIOS & rBIOS, 237 PageData & rPageHead); 238 239 storeError unusedPop ( 240 OStorePageBIOS & rBIOS, 241 PageData const & rPageHead); 242 243 storeError unusedPush ( 244 OStorePageBIOS & rBIOS, 245 sal_uInt32 nAddr); 246 247 /** verify (with repair). 248 */ 249 storeError verify (OStorePageBIOS & rBIOS); 250 }; 251 252 } // namespace store 253 254 /*======================================================================== 255 * 256 * SuperBlockPage implementation. 257 * 258 *======================================================================*/ 259 /* 260 * unusedHead(): get freelist head (alloc page, step 1). 261 */ 262 storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead) 263 { 264 storeError eErrCode = verify (rBIOS); 265 if (eErrCode != store_E_None) 266 return eErrCode; 267 268 // Check freelist head. 269 OStorePageLink const aListHead (m_aSuperOne.unusedHead()); 270 if (aListHead.location() == 0) 271 { 272 // Freelist empty, see SuperBlock::ctor(). 273 rPageHead.location (STORE_PAGE_NULL); 274 return store_E_None; 275 } 276 277 // Load PageHead. 278 eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize); 279 if (eErrCode != store_E_None) 280 return eErrCode; 281 282 eErrCode = rPageHead.verify (aListHead.location()); 283 if (eErrCode != store_E_None) 284 return eErrCode; 285 286 // Verify page is unused. 287 sal_uInt32 const nAddr = rPageHead.m_aUnused.location(); 288 OSL_POSTCOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedHead(): page not free"); 289 if (nAddr == STORE_PAGE_NULL) 290 { 291 // Page in use. 292 rPageHead.location (STORE_PAGE_NULL); 293 294 // Recovery: Reset freelist to empty. 295 m_aSuperOne.unusedReset(); 296 eErrCode = save (rBIOS); 297 } 298 return eErrCode; 299 } 300 301 /* 302 * unusedPop(): pop freelist head (alloc page, step 2). 303 */ 304 storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead) 305 { 306 sal_uInt32 const nAddr = rPageHead.m_aUnused.location(); 307 OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free"); 308 if (nAddr == STORE_PAGE_NULL) 309 return store_E_CantSeek; 310 311 // Pop from FreeList. 312 OStorePageLink const aListHead (nAddr); 313 m_aSuperOne.unusedRemove (aListHead); 314 return save (rBIOS); 315 } 316 317 /* 318 * unusedPush(): push new freelist head. 319 */ 320 storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr) 321 { 322 storeError eErrCode = verify (rBIOS); 323 if (eErrCode != store_E_None) 324 return eErrCode; 325 326 PageData aPageHead; 327 eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize); 328 if (eErrCode != store_E_None) 329 return eErrCode; 330 331 eErrCode = aPageHead.verify (nAddr); 332 if (eErrCode != store_E_None) 333 return eErrCode; 334 335 aPageHead.m_aUnused = m_aSuperOne.unusedHead(); 336 aPageHead.guard (nAddr); 337 338 eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize); 339 if (eErrCode != store_E_None) 340 return eErrCode; 341 342 OStorePageLink const aListHead (nAddr); 343 m_aSuperOne.unusedInsert(aListHead); 344 return save (rBIOS); 345 } 346 347 /* 348 * verify (with repair). 349 */ 350 storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS) 351 { 352 // Verify 1st copy. 353 storeError eErrCode = m_aSuperOne.verify(); 354 if (eErrCode == store_E_None) 355 { 356 // Ok. Verify 2nd copy. 357 eErrCode = m_aSuperTwo.verify(); 358 if (eErrCode == store_E_None) 359 { 360 // Ok. Ensure identical copies (1st copy wins). 361 if (!(m_aSuperOne == m_aSuperTwo)) 362 { 363 // Different. Replace 2nd copy with 1st copy. 364 m_aSuperTwo = m_aSuperOne; 365 366 // Write back. 367 if (rBIOS.isWriteable()) 368 eErrCode = rBIOS.write (0, this, theSize); 369 else 370 eErrCode = store_E_None; 371 } 372 } 373 else 374 { 375 // Failure. Replace 2nd copy with 1st copy. 376 m_aSuperTwo = m_aSuperOne; 377 378 // Write back. 379 if (rBIOS.isWriteable()) 380 eErrCode = rBIOS.write (0, this, theSize); 381 else 382 eErrCode = store_E_None; 383 } 384 } 385 else 386 { 387 // Failure. Verify 2nd copy. 388 eErrCode = m_aSuperTwo.verify(); 389 if (eErrCode == store_E_None) 390 { 391 // Ok. Replace 1st copy with 2nd copy. 392 m_aSuperOne = m_aSuperTwo; 393 394 // Write back. 395 if (rBIOS.isWriteable()) 396 eErrCode = rBIOS.write (0, this, theSize); 397 else 398 eErrCode = store_E_None; 399 } 400 else 401 { 402 // Double Failure. 403 OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.\n"); 404 } 405 } 406 407 // Done. 408 return eErrCode; 409 } 410 411 /*======================================================================== 412 * 413 * OStorePageBIOS::Ace implementation. 414 * 415 *======================================================================*/ 416 OStorePageBIOS::Ace::Ace() 417 : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0) 418 {} 419 420 OStorePageBIOS::Ace::~Ace() 421 { 422 m_next->m_prev = m_prev, m_prev->m_next = m_next; 423 } 424 425 int 426 SAL_CALL OStorePageBIOS::Ace::constructor (void * obj, void * /* arg */) 427 { 428 Ace * ace = static_cast<Ace*>(obj); 429 ace->m_next = ace->m_prev = ace; 430 return 1; 431 } 432 433 OStorePageBIOS::Ace * 434 OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr) 435 { 436 OStorePageBIOS::Ace * entry; 437 for (entry = head->m_next; entry != head; entry = entry->m_next) 438 { 439 if (entry->m_addr >= addr) 440 return entry; 441 } 442 return head; 443 } 444 445 void 446 OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry) 447 { 448 // insert entry at queue tail (before head). 449 entry->m_next = head; 450 entry->m_prev = head->m_prev; 451 head->m_prev = entry; 452 entry->m_prev->m_next = entry; 453 } 454 455 /*======================================================================== 456 * 457 * OStorePageBIOS::AceCache interface. 458 * 459 *======================================================================*/ 460 namespace store 461 { 462 463 class OStorePageBIOS::AceCache 464 { 465 rtl_cache_type * m_ace_cache; 466 467 public: 468 static AceCache & get(); 469 470 OStorePageBIOS::Ace * 471 create (sal_uInt32 addr, sal_uInt32 used = 1); 472 473 void 474 destroy (OStorePageBIOS::Ace * ace); 475 476 protected: 477 AceCache(); 478 ~AceCache(); 479 }; 480 481 } // namespace store 482 483 /*======================================================================== 484 * 485 * OStorePageBIOS::AceCache implementation. 486 * 487 *======================================================================*/ 488 extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*); 489 490 OStorePageBIOS::AceCache & 491 OStorePageBIOS::AceCache::get() 492 { 493 static AceCache g_ace_cache; 494 return g_ace_cache; 495 } 496 497 OStorePageBIOS::AceCache::AceCache() 498 { 499 m_ace_cache = rtl_cache_create ( 500 "store_ace_cache", 501 sizeof (OStorePageBIOS::Ace), 502 0, // objalign 503 reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor), 504 0, // destructor, 505 0, // reclaim, 506 0, // userarg, 507 0, // default source, 508 0 // flags 509 ); 510 } 511 512 OStorePageBIOS::AceCache::~AceCache() 513 { 514 rtl_cache_destroy (m_ace_cache), m_ace_cache = 0; 515 } 516 517 OStorePageBIOS::Ace * 518 OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used) 519 { 520 Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache)); 521 if (ace != 0) 522 { 523 // verify invariant state. 524 OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace)); 525 526 // initialize. 527 ace->m_addr = addr; 528 ace->m_used = used; 529 } 530 return ace; 531 } 532 533 void 534 OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace) 535 { 536 if (ace != 0) 537 { 538 // remove from queue (if any). 539 ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next; 540 541 // restore invariant state. 542 ace->m_next = ace->m_prev = ace; 543 544 // return to cache. 545 rtl_cache_free (m_ace_cache, ace); 546 } 547 } 548 549 /*======================================================================== 550 * 551 * OStorePageBIOS implementation. 552 * 553 *======================================================================*/ 554 /* 555 * OStorePageBIOS. 556 */ 557 OStorePageBIOS::OStorePageBIOS (void) 558 : m_xLockBytes (NULL), 559 m_pSuper (NULL), 560 m_bWriteable (false) 561 { 562 } 563 564 /* 565 * ~OStorePageBIOS. 566 */ 567 OStorePageBIOS::~OStorePageBIOS (void) 568 { 569 cleanup_Impl(); 570 } 571 572 /* 573 * initialize. 574 * Precond: none. 575 */ 576 storeError OStorePageBIOS::initialize ( 577 ILockBytes * pLockBytes, 578 storeAccessMode eAccessMode, 579 sal_uInt16 & rnPageSize) 580 { 581 // Acquire exclusive access. 582 osl::MutexGuard aGuard (m_aMutex); 583 584 // Initialize. 585 storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize); 586 if (eErrCode != store_E_None) 587 { 588 // Cleanup. 589 cleanup_Impl(); 590 } 591 return eErrCode; 592 } 593 594 /* 595 * initialize_Impl. 596 * Internal: Precond: exclusive access. 597 */ 598 storeError OStorePageBIOS::initialize_Impl ( 599 ILockBytes * pLockBytes, 600 storeAccessMode eAccessMode, 601 sal_uInt16 & rnPageSize) 602 { 603 // Cleanup. 604 cleanup_Impl(); 605 606 // Initialize. 607 m_xLockBytes = pLockBytes; 608 if (!m_xLockBytes.is()) 609 return store_E_InvalidParameter; 610 m_bWriteable = (eAccessMode != store_AccessReadOnly); 611 612 // Check access mode. 613 storeError eErrCode = store_E_None; 614 if (eAccessMode != store_AccessCreate) 615 { 616 // Load SuperBlock page. 617 if ((m_pSuper = new SuperBlockPage()) == 0) 618 return store_E_OutOfMemory; 619 620 eErrCode = read (0, m_pSuper, SuperBlockPage::theSize); 621 if (eErrCode == store_E_None) 622 { 623 // Verify SuperBlock page (with repair). 624 eErrCode = m_pSuper->verify (*this); 625 } 626 } 627 else 628 { 629 // Truncate to zero length. 630 eErrCode = m_xLockBytes->setSize(0); 631 if (eErrCode != store_E_None) 632 return eErrCode; 633 634 // Mark as not existing. 635 eErrCode = store_E_NotExists; 636 } 637 638 if (eErrCode != store_E_None) 639 { 640 // Check reason. 641 if (eErrCode != store_E_NotExists) 642 return eErrCode; 643 644 // Check mode. 645 if (eAccessMode == store_AccessReadOnly) 646 return store_E_NotExists; 647 if (eAccessMode == store_AccessReadWrite) 648 return store_E_NotExists; 649 650 // Check PageSize. 651 if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE)) 652 return store_E_InvalidParameter; 653 rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1)); 654 655 // Create initial page (w/ SuperBlock). 656 if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0) 657 return store_E_OutOfMemory; 658 eErrCode = m_pSuper->save (*this, rnPageSize); 659 } 660 if (eErrCode == store_E_None) 661 { 662 // Obtain page size. 663 rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize); 664 665 // Create page allocator. 666 eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize); 667 if (eErrCode != store_E_None) 668 return eErrCode; 669 670 // Create page cache. 671 eErrCode = PageCache_createInstance (m_xCache, rnPageSize); 672 } 673 return eErrCode; 674 } 675 676 /* 677 * cleanup_Impl. 678 * Internal: Precond: exclusive access. 679 */ 680 void OStorePageBIOS::cleanup_Impl() 681 { 682 // Check referer count. 683 if (m_ace_head.m_used > 0) 684 { 685 // Report remaining referer count. 686 OSL_TRACE("store::PageBIOS::cleanup_Impl(): referer count: %d\n", m_ace_head.m_used); 687 for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next) 688 { 689 m_ace_head.m_used -= ace->m_used; 690 AceCache::get().destroy (ace); 691 } 692 OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error"); 693 } 694 695 // Release SuperBlock page. 696 delete m_pSuper, m_pSuper = 0; 697 698 // Release PageCache. 699 m_xCache.clear(); 700 701 // Release PageAllocator. 702 m_xAllocator.clear(); 703 704 // Release LockBytes. 705 m_xLockBytes.clear(); 706 } 707 708 /* 709 * read. 710 * Low Level: Precond: initialized, exclusive access. 711 */ 712 storeError OStorePageBIOS::read ( 713 sal_uInt32 nAddr, void *pData, sal_uInt32 nSize) 714 { 715 // Check precond. 716 if (!m_xLockBytes.is()) 717 return store_E_InvalidAccess; 718 719 // Read Data. 720 return m_xLockBytes->readAt (nAddr, pData, nSize); 721 } 722 723 /* 724 * write. 725 * Low Level: Precond: initialized, writeable, exclusive access. 726 */ 727 storeError OStorePageBIOS::write ( 728 sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize) 729 { 730 // Check precond. 731 if (!m_xLockBytes.is()) 732 return store_E_InvalidAccess; 733 if (!m_bWriteable) 734 return store_E_AccessViolation; 735 736 // Write Data. 737 return m_xLockBytes->writeAt (nAddr, pData, nSize); 738 } 739 740 /* 741 * acquirePage. 742 * Precond: initialized. 743 */ 744 storeError OStorePageBIOS::acquirePage ( 745 const OStorePageDescriptor& rDescr, storeAccessMode eMode) 746 { 747 // Acquire exclusive access. 748 osl::MutexGuard aGuard (m_aMutex); 749 750 // Check precond. 751 if (!m_xLockBytes.is()) 752 return store_E_InvalidAccess; 753 754 // Check access mode. 755 if (!(m_bWriteable || (eMode == store_AccessReadOnly))) 756 return store_E_AccessViolation; 757 758 // Find access control list entry. 759 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr); 760 if (ace->m_addr == rDescr.m_nAddr) 761 { 762 // Acquire existing entry (with ShareDenyWrite). 763 if (eMode == store_AccessReadOnly) 764 ace->m_used += 1; 765 else 766 return store_E_AccessViolation; 767 } 768 else 769 { 770 // Insert new entry. 771 Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1); 772 if (!entry) 773 return store_E_OutOfMemory; 774 Ace::insert (ace, entry); 775 } 776 777 // Increment total referer count and finish. 778 m_ace_head.m_used += 1; 779 return store_E_None; 780 } 781 782 /* 783 * releasePage. 784 * Precond: initialized. 785 */ 786 storeError OStorePageBIOS::releasePage ( 787 const OStorePageDescriptor& rDescr, storeAccessMode /* eMode */) 788 { 789 // Acquire exclusive access. 790 osl::MutexGuard aGuard (m_aMutex); 791 792 // Check precond. 793 if (!m_xLockBytes.is()) 794 return store_E_InvalidAccess; 795 796 // Find access control list entry. 797 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr); 798 if (ace->m_addr != rDescr.m_nAddr) 799 return store_E_NotExists; 800 801 // Release existing entry. 802 if (ace->m_used > 1) 803 ace->m_used -= 1; 804 else 805 AceCache::get().destroy (ace); 806 807 // Decrement total referer count and finish. 808 m_ace_head.m_used -= 1; 809 return store_E_None; 810 } 811 812 /* 813 * getRefererCount. 814 * Precond: none. 815 */ 816 sal_uInt32 OStorePageBIOS::getRefererCount (void) 817 { 818 // Acquire exclusive access. 819 osl::MutexGuard aGuard (m_aMutex); 820 821 // Obtain total referer count. 822 return m_ace_head.m_used; 823 } 824 825 /* 826 * allocate. 827 * Precond: initialized, writeable. 828 */ 829 storeError OStorePageBIOS::allocate ( 830 OStorePageObject& rPage, Allocation eAlloc) 831 { 832 // Acquire exclusive access. 833 osl::MutexGuard aGuard (m_aMutex); 834 835 // Check precond. 836 if (!m_xLockBytes.is()) 837 return store_E_InvalidAccess; 838 if (!m_bWriteable) 839 return store_E_AccessViolation; 840 841 // Check allocation type. 842 storeError eErrCode = store_E_None; 843 if (eAlloc != ALLOCATE_EOF) 844 { 845 // Try freelist head. 846 PageData aPageHead; 847 eErrCode = m_pSuper->unusedHead (*this, aPageHead); 848 if (eErrCode != store_E_None) 849 return eErrCode; 850 851 sal_uInt32 const nAddr = aPageHead.location(); 852 if (nAddr != STORE_PAGE_NULL) 853 { 854 // Save page. 855 eErrCode = saveObjectAt_Impl (rPage, nAddr); 856 if (eErrCode != store_E_None) 857 return eErrCode; 858 859 // Pop freelist head and finish. 860 return m_pSuper->unusedPop (*this, aPageHead); 861 } 862 } 863 864 // Allocate from EOF. Determine current size. 865 sal_uInt32 nSize = STORE_PAGE_NULL; 866 eErrCode = m_xLockBytes->getSize (nSize); 867 if (eErrCode != store_E_None) 868 return eErrCode; 869 870 // Save page at current EOF. 871 return saveObjectAt_Impl (rPage, nSize); 872 } 873 874 /* 875 * free. 876 * Precond: initialized, writeable. 877 */ 878 storeError OStorePageBIOS::free (sal_uInt32 nAddr) 879 { 880 // Acquire exclusive access. 881 osl::MutexGuard aGuard (m_aMutex); 882 883 // Check precond. 884 if (!m_xLockBytes.is()) 885 return store_E_InvalidAccess; 886 if (!m_bWriteable) 887 return store_E_AccessViolation; 888 889 // Invalidate cache. 890 (void) m_xCache->removePageAt (nAddr); 891 892 // Push onto freelist. 893 return m_pSuper->unusedPush (*this, nAddr); 894 } 895 896 /* 897 * loadObjectAt. 898 * Precond: initialized, readable. 899 */ 900 storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr) 901 { 902 // Acquire exclusive access. 903 osl::MutexGuard aGuard (m_aMutex); 904 905 // Check precond. 906 if (!m_xLockBytes.is()) 907 return store_E_InvalidAccess; 908 909 return loadObjectAt_Impl (rPage, nAddr); 910 } 911 912 /* 913 * loadObjectAt_Impl. 914 * Internal: Precond: initialized, readable, exclusive access. 915 */ 916 storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr) 917 { 918 storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr); 919 if (eErrCode != store_E_NotExists) 920 return eErrCode; 921 922 // Read page. 923 eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr); 924 if (eErrCode != store_E_None) 925 return eErrCode; 926 927 // Verify page. 928 eErrCode = rPage.verify (nAddr); 929 if (eErrCode != store_E_None) 930 return eErrCode; 931 932 // Mark page as clean. 933 rPage.clean(); 934 935 // Cache page. 936 return m_xCache->insertPageAt (rPage.get(), nAddr); 937 } 938 939 /* 940 * saveObjectAt. 941 * Precond: initialized, writeable. 942 */ 943 storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr) 944 { 945 // Acquire exclusive access. 946 osl::MutexGuard aGuard (m_aMutex); 947 948 // Check precond. 949 if (!m_xLockBytes.is()) 950 return store_E_InvalidAccess; 951 if (!m_bWriteable) 952 return store_E_AccessViolation; 953 954 // Save Page. 955 return saveObjectAt_Impl (rPage, nAddr); 956 } 957 958 /* 959 * saveObjectAt_Impl. 960 * Internal: Precond: initialized, writeable, exclusive access. 961 */ 962 storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr) 963 { 964 // Guard page (incl. set location). 965 storeError eErrCode = rPage.guard (nAddr); 966 if (eErrCode != store_E_None) 967 return eErrCode; 968 969 // Write page. 970 eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr); 971 if (eErrCode != store_E_None) 972 return eErrCode; 973 974 // Mark page as clean. 975 rPage.clean(); 976 977 // Cache page. 978 return m_xCache->updatePageAt (rPage.get(), nAddr); 979 } 980 981 /* 982 * close. 983 * Precond: none. 984 */ 985 storeError OStorePageBIOS::close() 986 { 987 // Acquire exclusive access. 988 osl::MutexGuard aGuard (m_aMutex); 989 990 // Cleanup. 991 cleanup_Impl(); 992 993 // Done. 994 return store_E_None; 995 } 996 997 /* 998 * flush. 999 * Precond: initialized. 1000 */ 1001 storeError OStorePageBIOS::flush (void) 1002 { 1003 // Acquire exclusive access. 1004 osl::MutexGuard aGuard (m_aMutex); 1005 1006 // Check precond. 1007 if (!m_xLockBytes.is()) 1008 return store_E_InvalidAccess; 1009 1010 // Flush LockBytes and finish. 1011 return m_xLockBytes->flush(); 1012 } 1013 1014 /* 1015 * size. 1016 * Precond: initialized. 1017 */ 1018 storeError OStorePageBIOS::size (sal_uInt32 &rnSize) 1019 { 1020 // Acquire exclusive access. 1021 osl::MutexGuard aGuard (m_aMutex); 1022 1023 // Initialize [out] param. 1024 rnSize = 0; 1025 1026 // Check precond. 1027 if (!m_xLockBytes.is()) 1028 return store_E_InvalidAccess; 1029 1030 // Obtain LockBytes size. 1031 return m_xLockBytes->getSize (rnSize); 1032 } 1033 1034 /* 1035 * scanBegin. 1036 * Precond: initialized. 1037 */ 1038 storeError OStorePageBIOS::scanBegin ( 1039 ScanContext &rCtx, sal_uInt32 nMagic) 1040 { 1041 // Acquire exclusive access. 1042 osl::MutexGuard aGuard (m_aMutex); 1043 1044 // Initialize [out] param. 1045 rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0); 1046 rCtx.m_nSize = 0; 1047 rCtx.m_nMagic = nMagic; 1048 1049 // Check precond. 1050 if (!m_xLockBytes.is()) 1051 return store_E_InvalidAccess; 1052 1053 // Check SuperBlock page. 1054 storeError eErrCode = m_pSuper->verify (*this); 1055 if (eErrCode != store_E_None) 1056 { 1057 // Damaged. Determine page size (NYI). 1058 OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n"); 1059 return eErrCode; 1060 } 1061 1062 // Setup Context descriptor. 1063 rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr; 1064 rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize); 1065 rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize; 1066 1067 // Setup Context size. 1068 eErrCode = size (rCtx.m_nSize); 1069 if (eErrCode != store_E_None) 1070 rCtx.m_nSize = ((sal_uInt32)(~0)); 1071 1072 // Done. 1073 return store_E_None; 1074 } 1075 1076 /* 1077 * scanNext. 1078 * Precond: initialized. 1079 */ 1080 storeError OStorePageBIOS::scanNext ( 1081 ScanContext &rCtx, OStorePageObject &rPage) 1082 { 1083 // Acquire exclusive access. 1084 osl::MutexGuard aGuard (m_aMutex); 1085 1086 // Check precond. 1087 if (!m_xLockBytes.is()) 1088 return store_E_InvalidAccess; 1089 1090 // Setup PageHead. 1091 PageData aPageHead; 1092 1093 // Check context. 1094 while (rCtx.isValid()) 1095 { 1096 // Assign next location. 1097 sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr; 1098 rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize; 1099 1100 // Read PageHead. 1101 storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize); 1102 if (eErrCode != store_E_None) 1103 continue; 1104 1105 // Verify PageHead. 1106 eErrCode = aPageHead.verify (nAddr); 1107 if (eErrCode != store_E_None) 1108 continue; 1109 1110 // Check PageHead Magic number. 1111 if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic) 1112 continue; 1113 1114 // Check PageHead Unused link. 1115 if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL) 1116 continue; 1117 1118 // Load page. 1119 eErrCode = loadObjectAt_Impl (rPage, nAddr); 1120 if (eErrCode != store_E_None) 1121 continue; 1122 1123 // Deliver page. 1124 return store_E_None; 1125 } 1126 1127 // Done. 1128 return store_E_CantSeek; 1129 } 1130