xref: /aoo41x/main/store/source/storbios.cxx (revision cdf0e10c)
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