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