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