Branch libreoffice-5-0-4
[LibreOffice.git] / store / source / storbios.cxx
blob3f9ec2d9305235539de5be4c5cf48150961e776d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
22 #include "storbios.hxx"
24 #include "sal/types.h"
25 #include "sal/macros.h"
26 #include "sal/log.hxx"
28 #include "rtl/alloc.h"
29 #include "rtl/ref.hxx"
31 #include "osl/diagnose.h"
32 #include "osl/mutex.hxx"
34 #include "store/types.h"
35 #include "object.hxx"
36 #include "lockbyte.hxx"
37 #include "storcach.hxx"
39 using namespace store;
41 /*========================================================================
43 * OStoreSuperBlock.
45 *======================================================================*/
46 #define STORE_MAGIC_SUPERBLOCK sal_uInt32(0x484D5343)
48 struct OStoreSuperBlock
50 typedef OStorePageGuard G;
51 typedef OStorePageDescriptor D;
52 typedef OStorePageLink L;
54 /** Representation.
56 G m_aGuard;
57 D m_aDescr;
58 sal_uInt32 m_nMarked;
59 L m_aMarked;
60 sal_uInt32 m_nUnused;
61 L m_aUnused;
63 /** theSize.
65 static const size_t theSize = sizeof(G) + sizeof(D) + 2 * (sizeof(L) + sizeof(sal_uInt32));
67 /** Construction.
69 explicit OStoreSuperBlock (sal_uInt16 nPageSize)
70 : m_aGuard (STORE_MAGIC_SUPERBLOCK),
71 m_aDescr (nPageSize, nPageSize, STORE_MINIMUM_PAGESIZE),
72 m_nMarked (store::htonl(0)),
73 m_aMarked (0),
74 m_nUnused (store::htonl(0)),
75 m_aUnused (0)
78 /** Comparison.
80 bool operator== (const OStoreSuperBlock & rhs) const
82 return ((m_aGuard == rhs.m_aGuard ) &&
83 (m_aDescr == rhs.m_aDescr ) &&
84 (m_nMarked == rhs.m_nMarked) &&
85 (m_aMarked == rhs.m_aMarked) &&
86 (m_nUnused == rhs.m_nUnused) &&
87 (m_aUnused == rhs.m_aUnused) );
90 /** unused(Count|Head|Insert|Remove|Reset).
92 sal_uInt32 unusedCount() const
94 return store::ntohl(m_nUnused);
96 const L& unusedHead() const
98 return m_aUnused;
100 void unusedInsert (const L& rLink)
102 sal_uInt32 nUnused = unusedCount();
103 m_nUnused = store::htonl(nUnused + 1);
104 m_aUnused = rLink;
106 void unusedRemove (const L& rLink)
108 sal_uInt32 nUnused = unusedCount();
109 m_nUnused = store::htonl(nUnused - 1);
110 m_aUnused = rLink;
112 void unusedReset()
114 m_nUnused = store::htonl(0);
115 m_aUnused = L(0);
118 /** guard (external representation).
120 void guard()
122 sal_uInt32 nCRC32 = 0;
123 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
124 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
125 m_aGuard.m_nCRC32 = store::htonl(nCRC32);
128 /** verify (external representation).
130 storeError verify() const
132 sal_uInt32 nMagic = store::ntohl(m_aGuard.m_nMagic);
133 if (nMagic != STORE_MAGIC_SUPERBLOCK)
134 return store_E_WrongFormat;
136 sal_uInt32 nCRC32 = 0;
137 nCRC32 = rtl_crc32 (nCRC32, &m_aGuard.m_nMagic, sizeof(sal_uInt32));
138 nCRC32 = rtl_crc32 (nCRC32, &m_aDescr, theSize - sizeof(G));
139 if (m_aGuard.m_nCRC32 != store::htonl(nCRC32))
140 return store_E_InvalidChecksum;
141 else
142 return store_E_None;
146 /*========================================================================
148 * SuperBlockPage interface.
150 *======================================================================*/
151 namespace store
154 struct SuperBlockPage
156 typedef OStoreSuperBlock SuperBlock;
158 /** Representation.
160 SuperBlock m_aSuperOne;
161 SuperBlock m_aSuperTwo;
163 /** theSize.
165 static const size_t theSize = 2 * SuperBlock::theSize;
166 static const sal_uInt16 thePageSize = theSize;
167 static_assert(STORE_MINIMUM_PAGESIZE >= thePageSize, "must be at least thePageSize");
169 /** Allocation.
171 static void * operator new (size_t n)
173 return rtl_allocateMemory (sal::static_int_cast<sal_Size>(n));
175 static void operator delete (void * p)
177 rtl_freeMemory (p);
180 static void * operator new (SAL_UNUSED_PARAMETER size_t, sal_uInt16 nPageSize)
182 return rtl_allocateZeroMemory (sal::static_int_cast<sal_Size>(nPageSize));
184 static void operator delete (void * p, SAL_UNUSED_PARAMETER sal_uInt16)
186 rtl_freeMemory (p);
189 /** Construction.
191 explicit SuperBlockPage (sal_uInt16 nPageSize = thePageSize)
192 : m_aSuperOne(nPageSize),
193 m_aSuperTwo(nPageSize)
196 /** save.
198 storeError save (OStorePageBIOS & rBIOS, sal_uInt32 nSize = theSize)
200 m_aSuperOne.guard();
201 m_aSuperTwo = m_aSuperOne;
202 return rBIOS.write (0, this, nSize);
205 /** Page allocation.
207 storeError unusedHead (
208 OStorePageBIOS & rBIOS,
209 PageData & rPageHead);
211 storeError unusedPop (
212 OStorePageBIOS & rBIOS,
213 PageData const & rPageHead);
215 storeError unusedPush (
216 OStorePageBIOS & rBIOS,
217 sal_uInt32 nAddr);
219 /** verify (with repair).
221 storeError verify (OStorePageBIOS & rBIOS);
224 } // namespace store
226 /*========================================================================
228 * SuperBlockPage implementation.
230 *======================================================================*/
232 * unusedHead(): get freelist head (alloc page, step 1).
234 storeError SuperBlockPage::unusedHead (OStorePageBIOS & rBIOS, PageData & rPageHead)
236 storeError eErrCode = verify (rBIOS);
237 if (eErrCode != store_E_None)
238 return eErrCode;
240 // Check freelist head.
241 OStorePageLink const aListHead (m_aSuperOne.unusedHead());
242 if (aListHead.location() == 0)
244 // Freelist empty, see SuperBlock::ctor().
245 rPageHead.location (STORE_PAGE_NULL);
246 return store_E_None;
249 // Load PageHead.
250 eErrCode = rBIOS.read (aListHead.location(), &rPageHead, PageData::theSize);
251 if (eErrCode != store_E_None)
252 return eErrCode;
254 eErrCode = rPageHead.verify (aListHead.location());
255 if (eErrCode != store_E_None)
256 return eErrCode;
258 // Verify page is unused.
259 sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
260 if (nAddr == STORE_PAGE_NULL)
262 SAL_WARN("store", "store::SuperBlock::unusedHead(): page not free");
264 // Page in use.
265 rPageHead.location (STORE_PAGE_NULL);
267 // Recovery: Reset freelist to empty.
268 m_aSuperOne.unusedReset();
269 eErrCode = save (rBIOS);
271 return eErrCode;
275 * unusedPop(): pop freelist head (alloc page, step 2).
277 storeError SuperBlockPage::unusedPop (OStorePageBIOS & rBIOS, PageData const & rPageHead)
279 sal_uInt32 const nAddr = rPageHead.m_aUnused.location();
280 OSL_PRECOND(nAddr != STORE_PAGE_NULL, "store::SuperBlock::unusedPop(): page not free");
281 if (nAddr == STORE_PAGE_NULL)
282 return store_E_CantSeek;
284 // Pop from FreeList.
285 OStorePageLink const aListHead (nAddr);
286 m_aSuperOne.unusedRemove (aListHead);
287 return save (rBIOS);
291 * unusedPush(): push new freelist head.
293 storeError SuperBlockPage::unusedPush (OStorePageBIOS & rBIOS, sal_uInt32 nAddr)
295 storeError eErrCode = verify (rBIOS);
296 if (eErrCode != store_E_None)
297 return eErrCode;
299 PageData aPageHead;
300 eErrCode = rBIOS.read (nAddr, &aPageHead, PageData::theSize);
301 if (eErrCode != store_E_None)
302 return eErrCode;
304 eErrCode = aPageHead.verify (nAddr);
305 if (eErrCode != store_E_None)
306 return eErrCode;
308 aPageHead.m_aUnused = m_aSuperOne.unusedHead();
309 aPageHead.guard (nAddr);
311 eErrCode = rBIOS.write (nAddr, &aPageHead, PageData::theSize);
312 if (eErrCode != store_E_None)
313 return eErrCode;
315 OStorePageLink const aListHead (nAddr);
316 m_aSuperOne.unusedInsert(aListHead);
317 return save (rBIOS);
321 * verify (with repair).
323 storeError SuperBlockPage::verify (OStorePageBIOS & rBIOS)
325 // Verify 1st copy.
326 storeError eErrCode = m_aSuperOne.verify();
327 if (eErrCode == store_E_None)
329 // Ok. Verify 2nd copy.
330 eErrCode = m_aSuperTwo.verify();
331 if (eErrCode == store_E_None)
333 // Ok. Ensure identical copies (1st copy wins).
334 if (!(m_aSuperOne == m_aSuperTwo))
336 // Different. Replace 2nd copy with 1st copy.
337 m_aSuperTwo = m_aSuperOne;
339 // Write back.
340 if (rBIOS.isWriteable())
341 eErrCode = rBIOS.write (0, this, theSize);
342 else
343 eErrCode = store_E_None;
346 else
348 // Failure. Replace 2nd copy with 1st copy.
349 m_aSuperTwo = m_aSuperOne;
351 // Write back.
352 if (rBIOS.isWriteable())
353 eErrCode = rBIOS.write (0, this, theSize);
354 else
355 eErrCode = store_E_None;
358 else
360 // Failure. Verify 2nd copy.
361 eErrCode = m_aSuperTwo.verify();
362 if (eErrCode == store_E_None)
364 // Ok. Replace 1st copy with 2nd copy.
365 m_aSuperOne = m_aSuperTwo;
367 // Write back.
368 if (rBIOS.isWriteable())
369 eErrCode = rBIOS.write (0, this, theSize);
370 else
371 eErrCode = store_E_None;
373 else
375 // Double Failure.
376 OSL_TRACE("OStoreSuperBlockPage::verify(): double failure.");
380 // Done.
381 return eErrCode;
384 /*========================================================================
386 * OStorePageBIOS::Ace implementation.
388 *======================================================================*/
389 OStorePageBIOS::Ace::Ace()
390 : m_next (this), m_prev (this), m_addr (STORE_PAGE_NULL), m_used (0)
393 OStorePageBIOS::Ace::~Ace()
395 m_next->m_prev = m_prev, m_prev->m_next = m_next;
399 SAL_CALL OStorePageBIOS::Ace::constructor (
400 void * obj, SAL_UNUSED_PARAMETER void * /* arg */)
402 Ace * ace = static_cast<Ace*>(obj);
403 ace->m_next = ace->m_prev = ace;
404 return 1;
407 OStorePageBIOS::Ace *
408 OStorePageBIOS::Ace::find (OStorePageBIOS::Ace * head, sal_uInt32 addr)
410 OStorePageBIOS::Ace * entry;
411 for (entry = head->m_next; entry != head; entry = entry->m_next)
413 if (entry->m_addr >= addr)
414 return entry;
416 return head;
419 void
420 OStorePageBIOS::Ace::insert (OStorePageBIOS::Ace * head, OStorePageBIOS::Ace * entry)
422 // insert entry at queue tail (before head).
423 entry->m_next = head;
424 entry->m_prev = head->m_prev;
425 head->m_prev = entry;
426 entry->m_prev->m_next = entry;
429 /*========================================================================
431 * OStorePageBIOS::AceCache interface.
433 *======================================================================*/
434 namespace store
437 class OStorePageBIOS::AceCache
439 rtl_cache_type * m_ace_cache;
441 public:
442 static AceCache & get();
444 OStorePageBIOS::Ace *
445 create (sal_uInt32 addr, sal_uInt32 used = 1);
447 void
448 destroy (OStorePageBIOS::Ace * ace);
450 protected:
451 AceCache();
452 ~AceCache();
455 } // namespace store
457 /*========================================================================
459 * OStorePageBIOS::AceCache implementation.
461 *======================================================================*/
462 extern "C" typedef int (SAL_CALL * ace_constructor_type)(void*,void*);
464 OStorePageBIOS::AceCache &
465 OStorePageBIOS::AceCache::get()
467 static AceCache g_ace_cache;
468 return g_ace_cache;
471 OStorePageBIOS::AceCache::AceCache()
473 m_ace_cache = rtl_cache_create (
474 "store_ace_cache",
475 sizeof (OStorePageBIOS::Ace),
476 0, // objalign
477 reinterpret_cast<ace_constructor_type>( OStorePageBIOS::Ace::constructor),
478 0, // destructor,
479 0, // reclaim,
480 0, // userarg,
481 0, // default source,
482 0 // flags
486 OStorePageBIOS::AceCache::~AceCache()
488 rtl_cache_destroy (m_ace_cache), m_ace_cache = 0;
491 OStorePageBIOS::Ace *
492 OStorePageBIOS::AceCache::create (sal_uInt32 addr, sal_uInt32 used)
494 Ace * ace = static_cast<Ace*>(rtl_cache_alloc (m_ace_cache));
495 if (ace != 0)
497 // verify invariant state.
498 OSL_ASSERT((ace->m_next == ace) && (ace->m_prev == ace));
500 // initialize.
501 ace->m_addr = addr;
502 ace->m_used = used;
504 return ace;
507 void
508 OStorePageBIOS::AceCache::destroy (OStorePageBIOS::Ace * ace)
510 if (ace != 0)
512 // remove from queue (if any).
513 ace->m_next->m_prev = ace->m_prev, ace->m_prev->m_next = ace->m_next;
515 // restore invariant state.
516 ace->m_next = ace->m_prev = ace;
518 // return to cache.
519 rtl_cache_free (m_ace_cache, ace);
523 /*========================================================================
525 * OStorePageBIOS implementation.
527 *======================================================================*/
529 * OStorePageBIOS.
531 OStorePageBIOS::OStorePageBIOS()
532 : m_xLockBytes (NULL),
533 m_pSuper (NULL),
534 m_bWriteable (false)
539 * ~OStorePageBIOS.
541 OStorePageBIOS::~OStorePageBIOS()
543 cleanup_Impl();
547 * initialize.
548 * Precond: none.
550 storeError OStorePageBIOS::initialize (
551 ILockBytes * pLockBytes,
552 storeAccessMode eAccessMode,
553 sal_uInt16 & rnPageSize)
555 // Acquire exclusive access.
556 osl::MutexGuard aGuard (m_aMutex);
558 // Initialize.
559 storeError eErrCode = initialize_Impl (pLockBytes, eAccessMode, rnPageSize);
560 if (eErrCode != store_E_None)
562 // Cleanup.
563 cleanup_Impl();
565 return eErrCode;
569 * initialize_Impl.
570 * Internal: Precond: exclusive access.
572 storeError OStorePageBIOS::initialize_Impl (
573 ILockBytes * pLockBytes,
574 storeAccessMode eAccessMode,
575 sal_uInt16 & rnPageSize)
577 // Cleanup.
578 cleanup_Impl();
580 // Initialize.
581 m_xLockBytes = pLockBytes;
582 if (!m_xLockBytes.is())
583 return store_E_InvalidParameter;
584 m_bWriteable = (eAccessMode != store_AccessReadOnly);
586 // Check access mode.
587 storeError eErrCode = store_E_None;
588 if (eAccessMode != store_AccessCreate)
590 // Load SuperBlock page.
591 if ((m_pSuper = new SuperBlockPage()) == 0)
592 return store_E_OutOfMemory;
594 eErrCode = read (0, m_pSuper, SuperBlockPage::theSize);
595 if (eErrCode == store_E_None)
597 // Verify SuperBlock page (with repair).
598 eErrCode = m_pSuper->verify (*this);
601 else
603 // Truncate to zero length.
604 eErrCode = m_xLockBytes->setSize(0);
605 if (eErrCode != store_E_None)
606 return eErrCode;
608 // Mark as not existing.
609 eErrCode = store_E_NotExists;
612 if (eErrCode != store_E_None)
614 // Check reason.
615 if (eErrCode != store_E_NotExists)
616 return eErrCode;
618 // Check mode.
619 if (eAccessMode == store_AccessReadOnly)
620 return store_E_NotExists;
621 if (eAccessMode == store_AccessReadWrite)
622 return store_E_NotExists;
624 // Check PageSize.
625 if ((STORE_MINIMUM_PAGESIZE > rnPageSize) || (rnPageSize > STORE_MAXIMUM_PAGESIZE))
626 return store_E_InvalidParameter;
627 rnPageSize = ((rnPageSize + STORE_MINIMUM_PAGESIZE - 1) & ~(STORE_MINIMUM_PAGESIZE - 1));
629 // Create initial page (w/ SuperBlock).
630 if ((m_pSuper = new(rnPageSize) SuperBlockPage(rnPageSize)) == 0)
631 return store_E_OutOfMemory;
632 eErrCode = m_pSuper->save (*this, rnPageSize);
634 if (eErrCode == store_E_None)
636 // Obtain page size.
637 rnPageSize = store::ntohs(m_pSuper->m_aSuperOne.m_aDescr.m_nSize);
639 // Create page allocator.
640 eErrCode = m_xLockBytes->initialize (m_xAllocator, rnPageSize);
641 if (eErrCode != store_E_None)
642 return eErrCode;
644 // Create page cache.
645 eErrCode = PageCache_createInstance (m_xCache, rnPageSize);
647 return eErrCode;
651 * cleanup_Impl.
652 * Internal: Precond: exclusive access.
654 void OStorePageBIOS::cleanup_Impl()
656 // Check referer count.
657 if (m_ace_head.m_used > 0)
659 // Report remaining referer count.
660 SAL_INFO("store", "referer count: " << m_ace_head.m_used);
661 for (Ace * ace = m_ace_head.m_next; ace != &m_ace_head; ace = m_ace_head.m_next)
663 m_ace_head.m_used -= ace->m_used;
664 AceCache::get().destroy (ace);
666 OSL_ENSURE(m_ace_head.m_used == 0, "store::PageBIOS::cleanup_Impl(): logic error");
669 // Release SuperBlock page.
670 delete m_pSuper, m_pSuper = 0;
672 // Release PageCache.
673 m_xCache.clear();
675 // Release PageAllocator.
676 m_xAllocator.clear();
678 // Release LockBytes.
679 m_xLockBytes.clear();
683 * read.
684 * Low Level: Precond: initialized, exclusive access.
686 storeError OStorePageBIOS::read (
687 sal_uInt32 nAddr, void *pData, sal_uInt32 nSize)
689 // Check precond.
690 if (!m_xLockBytes.is())
691 return store_E_InvalidAccess;
693 // Read Data.
694 return m_xLockBytes->readAt (nAddr, pData, nSize);
698 * write.
699 * Low Level: Precond: initialized, writeable, exclusive access.
701 storeError OStorePageBIOS::write (
702 sal_uInt32 nAddr, const void *pData, sal_uInt32 nSize)
704 // Check precond.
705 if (!m_xLockBytes.is())
706 return store_E_InvalidAccess;
707 if (!m_bWriteable)
708 return store_E_AccessViolation;
710 // Write Data.
711 return m_xLockBytes->writeAt (nAddr, pData, nSize);
715 * acquirePage.
716 * Precond: initialized.
718 storeError OStorePageBIOS::acquirePage (
719 const OStorePageDescriptor& rDescr, storeAccessMode eMode)
721 // Acquire exclusive access.
722 osl::MutexGuard aGuard (m_aMutex);
724 // Check precond.
725 if (!m_xLockBytes.is())
726 return store_E_InvalidAccess;
728 // Check access mode.
729 if (!(m_bWriteable || (eMode == store_AccessReadOnly)))
730 return store_E_AccessViolation;
732 // Find access control list entry.
733 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
734 if (ace->m_addr == rDescr.m_nAddr)
736 // Acquire existing entry (with ShareDenyWrite).
737 if (eMode == store_AccessReadOnly)
738 ace->m_used += 1;
739 else
740 return store_E_AccessViolation;
742 else
744 // Insert new entry.
745 Ace * entry = AceCache::get().create (rDescr.m_nAddr, 1);
746 if (!entry)
747 return store_E_OutOfMemory;
748 Ace::insert (ace, entry);
751 // Increment total referer count and finish.
752 m_ace_head.m_used += 1;
753 return store_E_None;
757 * releasePage.
758 * Precond: initialized.
760 storeError OStorePageBIOS::releasePage (const OStorePageDescriptor& rDescr)
762 // Acquire exclusive access.
763 osl::MutexGuard aGuard (m_aMutex);
765 // Check precond.
766 if (!m_xLockBytes.is())
767 return store_E_InvalidAccess;
769 // Find access control list entry.
770 Ace * ace = Ace::find (&m_ace_head, rDescr.m_nAddr);
771 if (ace->m_addr != rDescr.m_nAddr)
772 return store_E_NotExists;
774 // Release existing entry.
775 if (ace->m_used > 1)
776 ace->m_used -= 1;
777 else
778 AceCache::get().destroy (ace);
780 // Decrement total referer count and finish.
781 m_ace_head.m_used -= 1;
782 return store_E_None;
786 * getRefererCount.
787 * Precond: none.
789 sal_uInt32 OStorePageBIOS::getRefererCount()
791 // Acquire exclusive access.
792 osl::MutexGuard aGuard (m_aMutex);
794 // Obtain total referer count.
795 return m_ace_head.m_used;
799 * allocate.
800 * Precond: initialized, writeable.
802 storeError OStorePageBIOS::allocate (
803 OStorePageObject& rPage, Allocation eAlloc)
805 // Acquire exclusive access.
806 osl::MutexGuard aGuard (m_aMutex);
808 // Check precond.
809 if (!m_xLockBytes.is())
810 return store_E_InvalidAccess;
811 if (!m_bWriteable)
812 return store_E_AccessViolation;
814 // Check allocation type.
815 storeError eErrCode = store_E_None;
816 if (eAlloc != ALLOCATE_EOF)
818 // Try freelist head.
819 PageData aPageHead;
820 eErrCode = m_pSuper->unusedHead (*this, aPageHead);
821 if (eErrCode != store_E_None)
822 return eErrCode;
824 sal_uInt32 const nAddr = aPageHead.location();
825 if (nAddr != STORE_PAGE_NULL)
827 // Save page.
828 eErrCode = saveObjectAt_Impl (rPage, nAddr);
829 if (eErrCode != store_E_None)
830 return eErrCode;
832 // Pop freelist head and finish.
833 return m_pSuper->unusedPop (*this, aPageHead);
837 // Allocate from EOF. Determine current size.
838 sal_uInt32 nSize = STORE_PAGE_NULL;
839 eErrCode = m_xLockBytes->getSize (nSize);
840 if (eErrCode != store_E_None)
841 return eErrCode;
843 // Save page at current EOF.
844 return saveObjectAt_Impl (rPage, nSize);
848 * free.
849 * Precond: initialized, writeable.
851 storeError OStorePageBIOS::free (sal_uInt32 nAddr)
853 // Acquire exclusive access.
854 osl::MutexGuard aGuard (m_aMutex);
856 // Check precond.
857 if (!m_xLockBytes.is())
858 return store_E_InvalidAccess;
859 if (!m_bWriteable)
860 return store_E_AccessViolation;
862 // Invalidate cache.
863 (void) m_xCache->removePageAt (nAddr);
865 // Push onto freelist.
866 return m_pSuper->unusedPush (*this, nAddr);
870 * loadObjectAt.
871 * Precond: initialized, readable.
873 storeError OStorePageBIOS::loadObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
875 // Acquire exclusive access.
876 osl::MutexGuard aGuard (m_aMutex);
878 // Check precond.
879 if (!m_xLockBytes.is())
880 return store_E_InvalidAccess;
882 return loadObjectAt_Impl (rPage, nAddr);
886 * loadObjectAt_Impl.
887 * Internal: Precond: initialized, readable, exclusive access.
889 storeError OStorePageBIOS::loadObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
891 storeError eErrCode = m_xCache->lookupPageAt (rPage.get(), nAddr);
892 if (eErrCode != store_E_NotExists)
893 return eErrCode;
895 // Read page.
896 eErrCode = m_xLockBytes->readPageAt (rPage.get(), nAddr);
897 if (eErrCode != store_E_None)
898 return eErrCode;
900 // Verify page.
901 eErrCode = rPage.verify (nAddr);
902 if (eErrCode != store_E_None)
903 return eErrCode;
905 // Mark page as clean.
906 rPage.clean();
908 // Cache page.
909 return m_xCache->insertPageAt (rPage.get(), nAddr);
913 * saveObjectAt.
914 * Precond: initialized, writeable.
916 storeError OStorePageBIOS::saveObjectAt (OStorePageObject & rPage, sal_uInt32 nAddr)
918 // Acquire exclusive access.
919 osl::MutexGuard aGuard (m_aMutex);
921 // Check precond.
922 if (!m_xLockBytes.is())
923 return store_E_InvalidAccess;
924 if (!m_bWriteable)
925 return store_E_AccessViolation;
927 // Save Page.
928 return saveObjectAt_Impl (rPage, nAddr);
932 * saveObjectAt_Impl.
933 * Internal: Precond: initialized, writeable, exclusive access.
935 storeError OStorePageBIOS::saveObjectAt_Impl (OStorePageObject & rPage, sal_uInt32 nAddr)
937 // Guard page (incl. set location).
938 storeError eErrCode = rPage.guard (nAddr);
939 if (eErrCode != store_E_None)
940 return eErrCode;
942 // Write page.
943 eErrCode = m_xLockBytes->writePageAt(rPage.get(), nAddr);
944 if (eErrCode != store_E_None)
945 return eErrCode;
947 // Mark page as clean.
948 rPage.clean();
950 // Cache page.
951 return m_xCache->updatePageAt (rPage.get(), nAddr);
955 * close.
956 * Precond: none.
958 storeError OStorePageBIOS::close()
960 // Acquire exclusive access.
961 osl::MutexGuard aGuard (m_aMutex);
963 // Cleanup.
964 cleanup_Impl();
966 // Done.
967 return store_E_None;
971 * flush.
972 * Precond: initialized.
974 storeError OStorePageBIOS::flush()
976 // Acquire exclusive access.
977 osl::MutexGuard aGuard (m_aMutex);
979 // Check precond.
980 if (!m_xLockBytes.is())
981 return store_E_InvalidAccess;
983 // Flush LockBytes and finish.
984 return m_xLockBytes->flush();
988 * size.
989 * Precond: initialized.
991 storeError OStorePageBIOS::size (sal_uInt32 &rnSize)
993 // Acquire exclusive access.
994 osl::MutexGuard aGuard (m_aMutex);
996 // Initialize [out] param.
997 rnSize = 0;
999 // Check precond.
1000 if (!m_xLockBytes.is())
1001 return store_E_InvalidAccess;
1003 // Obtain LockBytes size.
1004 return m_xLockBytes->getSize (rnSize);
1008 * scanBegin.
1009 * Precond: initialized.
1011 storeError OStorePageBIOS::scanBegin (
1012 ScanContext &rCtx, sal_uInt32 nMagic)
1014 // Acquire exclusive access.
1015 osl::MutexGuard aGuard (m_aMutex);
1017 // Initialize [out] param.
1018 rCtx.m_aDescr = OStorePageDescriptor(0, 0, 0);
1019 rCtx.m_nSize = 0;
1020 rCtx.m_nMagic = nMagic;
1022 // Check precond.
1023 if (!m_xLockBytes.is())
1024 return store_E_InvalidAccess;
1026 // Check SuperBlock page.
1027 storeError eErrCode = m_pSuper->verify (*this);
1028 if (eErrCode != store_E_None)
1030 // Damaged. Determine page size (NYI).
1031 OSL_TRACE ("OStorePageBIOS::scanBegin(): damaged.\n");
1032 return eErrCode;
1035 // Setup Context descriptor.
1036 rCtx.m_aDescr = m_pSuper->m_aSuperOne.m_aDescr;
1037 rCtx.m_aDescr.m_nSize = store::ntohs(rCtx.m_aDescr.m_nSize);
1038 rCtx.m_aDescr.m_nAddr = rCtx.m_aDescr.m_nSize;
1040 // Setup Context size.
1041 eErrCode = size (rCtx.m_nSize);
1042 if (eErrCode != store_E_None)
1043 rCtx.m_nSize = ((sal_uInt32)(~0));
1045 // Done.
1046 return store_E_None;
1050 * scanNext.
1051 * Precond: initialized.
1053 storeError OStorePageBIOS::scanNext (
1054 ScanContext &rCtx, OStorePageObject &rPage)
1056 // Acquire exclusive access.
1057 osl::MutexGuard aGuard (m_aMutex);
1059 // Check precond.
1060 if (!m_xLockBytes.is())
1061 return store_E_InvalidAccess;
1063 // Setup PageHead.
1064 PageData aPageHead;
1066 // Check context.
1067 while (rCtx.isValid())
1069 // Assign next location.
1070 sal_uInt32 nAddr = rCtx.m_aDescr.m_nAddr;
1071 rCtx.m_aDescr.m_nAddr += rCtx.m_aDescr.m_nSize;
1073 // Read PageHead.
1074 storeError eErrCode = read (nAddr, &aPageHead, PageData::theSize);
1075 if (eErrCode != store_E_None)
1076 continue;
1078 // Verify PageHead.
1079 eErrCode = aPageHead.verify (nAddr);
1080 if (eErrCode != store_E_None)
1081 continue;
1083 // Check PageHead Magic number.
1084 if (aPageHead.m_aGuard.m_nMagic != rCtx.m_nMagic)
1085 continue;
1087 // Check PageHead Unused link.
1088 if (aPageHead.m_aUnused.m_nAddr != STORE_PAGE_NULL)
1089 continue;
1091 // Load page.
1092 eErrCode = loadObjectAt_Impl (rPage, nAddr);
1093 if (eErrCode != store_E_None)
1094 continue;
1096 // Deliver page.
1097 return store_E_None;
1100 // Done.
1101 return store_E_CantSeek;
1104 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */