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