xref: /trunk/main/store/source/stordata.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 "stordata.hxx"
32 
33 #include "sal/types.h"
34 #include "osl/diagnose.h"
35 
36 #include "store/types.h"
37 #include "storbase.hxx"
38 #include "storbios.hxx"
39 
40 using namespace store;
41 
42 /*========================================================================
43  *
44  * OStoreDataPageObject implementation.
45  *
46  *======================================================================*/
47 /*
48  * guard.
49  */
50 storeError OStoreDataPageObject::guard (sal_uInt32 nAddr)
51 {
52     return PageHolderObject< page >::guard (m_xPage, nAddr);
53 }
54 
55 /*
56  * verify.
57  */
58 storeError OStoreDataPageObject::verify (sal_uInt32 nAddr) const
59 {
60     return PageHolderObject< page >::verify (m_xPage, nAddr);
61 }
62 
63 /*========================================================================
64  *
65  * OStoreIndirectionPageObject implementation.
66  *
67  *======================================================================*/
68 /*
69   * store_truncate_Impl (single indirect page).
70   */
71 static storeError store_truncate_Impl (
72     sal_uInt32      nAddr,
73     sal_uInt16      nSingle,
74     OStorePageBIOS &rBIOS)
75 {
76     if (nAddr != STORE_PAGE_NULL)
77     {
78         // Load single indirect page.
79         OStoreIndirectionPageObject aSingle;
80         storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr);
81         if (eErrCode == store_E_None)
82         {
83             // Truncate to 'nSingle' direct pages.
84             eErrCode = aSingle.truncate (nSingle, rBIOS);
85             if (eErrCode != store_E_None)
86                 return eErrCode;
87         }
88         else
89         {
90             if (eErrCode != store_E_InvalidChecksum)
91                 return eErrCode;
92         }
93 
94         // Check for complete truncation.
95         if (nSingle == 0)
96         {
97             // Free single indirect page.
98             eErrCode = rBIOS.free (nAddr);
99             if (eErrCode != store_E_None)
100                 return eErrCode;
101         }
102     }
103     return store_E_None;
104 }
105 
106 /*
107  * store_truncate_Impl (double indirect page).
108  */
109 static storeError store_truncate_Impl (
110     sal_uInt32       nAddr,
111     sal_uInt16       nDouble,
112     sal_uInt16       nSingle,
113     OStorePageBIOS  &rBIOS)
114 {
115     if (nAddr != STORE_PAGE_NULL)
116     {
117         // Load double indirect page.
118         OStoreIndirectionPageObject aDouble;
119         storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr);
120         if (eErrCode == store_E_None)
121         {
122             // Truncate to 'nDouble', 'nSingle' pages.
123             eErrCode = aDouble.truncate (nDouble, nSingle, rBIOS);
124             if (eErrCode != store_E_None)
125                 return eErrCode;
126         }
127         else
128         {
129             if (eErrCode != store_E_InvalidChecksum)
130                 return eErrCode;
131         }
132 
133         // Check for complete truncation.
134         if ((nDouble + nSingle) == 0)
135         {
136             // Free double indirect page.
137             eErrCode = rBIOS.free (nAddr);
138             if (eErrCode != store_E_None)
139                 return eErrCode;
140         }
141     }
142     return store_E_None;
143 }
144 
145 /*
146  * store_truncate_Impl (triple indirect page).
147  */
148 static storeError store_truncate_Impl (
149     sal_uInt32       nAddr,
150     sal_uInt16       nTriple,
151     sal_uInt16       nDouble,
152     sal_uInt16       nSingle,
153     OStorePageBIOS  &rBIOS)
154 {
155     if (nAddr != STORE_PAGE_NULL)
156     {
157         // Load triple indirect page.
158         OStoreIndirectionPageObject aTriple;
159         storeError eErrCode = rBIOS.loadObjectAt (aTriple, nAddr);
160         if (eErrCode != store_E_None)
161             return eErrCode;
162 
163         // Truncate to 'nTriple', 'nDouble', 'nSingle' pages.
164         eErrCode = aTriple.truncate (nTriple, nDouble, nSingle, rBIOS);
165         if (eErrCode != store_E_None)
166             return eErrCode;
167 
168         // Check for complete truncation.
169         if ((nTriple + nDouble + nSingle) == 0)
170         {
171             // Free triple indirect page.
172             eErrCode = rBIOS.free (nAddr);
173             if (eErrCode != store_E_None)
174                 return eErrCode;
175         }
176     }
177     return store_E_None;
178 }
179 
180 /*
181  * loadOrCreate.
182  */
183 storeError OStoreIndirectionPageObject::loadOrCreate (
184     sal_uInt32       nAddr,
185     OStorePageBIOS & rBIOS)
186 {
187     if (nAddr == STORE_PAGE_NULL)
188     {
189         storeError eErrCode = construct<page>(rBIOS.allocator());
190         if (eErrCode != store_E_None)
191             return eErrCode;
192 
193         eErrCode = rBIOS.allocate (*this);
194         if (eErrCode != store_E_None)
195             return eErrCode;
196 
197         // Save location pending at caller.
198         return store_E_Pending;
199     }
200     return rBIOS.loadObjectAt (*this, nAddr);
201 }
202 
203 /*
204  * guard.
205  */
206 storeError OStoreIndirectionPageObject::guard (sal_uInt32 nAddr)
207 {
208     return PageHolderObject< page >::guard (m_xPage, nAddr);
209 }
210 
211 /*
212  * verify.
213  */
214 storeError OStoreIndirectionPageObject::verify (sal_uInt32 nAddr) const
215 {
216     return PageHolderObject< page >::verify (m_xPage, nAddr);
217 }
218 
219 /*
220  * read (single indirect).
221  */
222 storeError OStoreIndirectionPageObject::read (
223     sal_uInt16             nSingle,
224     OStoreDataPageObject  &rData,
225     OStorePageBIOS        &rBIOS)
226 {
227     PageHolderObject< page > xImpl (m_xPage);
228     page const & rPage = (*xImpl);
229 
230     // Check arguments.
231     sal_uInt16 const nLimit = rPage.capacityCount();
232     if (!(nSingle < nLimit))
233         return store_E_InvalidAccess;
234 
235     // Obtain data page location.
236     sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]);
237     if (nAddr == STORE_PAGE_NULL)
238         return store_E_NotExists;
239 
240     // Load data page and leave.
241     return rBIOS.loadObjectAt (rData, nAddr);
242 }
243 
244 /*
245  * read (double indirect).
246  */
247 storeError OStoreIndirectionPageObject::read (
248     sal_uInt16             nDouble,
249     sal_uInt16             nSingle,
250     OStoreDataPageObject  &rData,
251     OStorePageBIOS        &rBIOS)
252 {
253     PageHolderObject< page > xImpl (m_xPage);
254     page const & rPage = (*xImpl);
255 
256     // Check arguments.
257     sal_uInt16 const nLimit = rPage.capacityCount();
258     if (!((nDouble < nLimit) && (nSingle < nLimit)))
259         return store_E_InvalidAccess;
260 
261     // Check single indirect page location.
262     sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nDouble]);
263     if (nAddr == STORE_PAGE_NULL)
264         return store_E_NotExists;
265 
266     // Load single indirect page.
267     OStoreIndirectionPageObject aSingle;
268     storeError eErrCode = rBIOS.loadObjectAt (aSingle, nAddr);
269     if (eErrCode != store_E_None)
270         return eErrCode;
271 
272     // Read single indirect and leave.
273     return aSingle.read (nSingle, rData, rBIOS);
274 }
275 
276 /*
277  * read (triple indirect).
278  */
279 storeError OStoreIndirectionPageObject::read (
280     sal_uInt16             nTriple,
281     sal_uInt16             nDouble,
282     sal_uInt16             nSingle,
283     OStoreDataPageObject  &rData,
284     OStorePageBIOS        &rBIOS)
285 {
286     PageHolderObject< page > xImpl (m_xPage);
287     page const & rPage = (*xImpl);
288 
289     // Check arguments.
290     sal_uInt16 const nLimit = rPage.capacityCount();
291     if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit)))
292         return store_E_InvalidAccess;
293 
294     // Check double indirect page location.
295     sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nTriple]);
296     if (nAddr == STORE_PAGE_NULL)
297         return store_E_NotExists;
298 
299     // Load double indirect page.
300     OStoreIndirectionPageObject aDouble;
301     storeError eErrCode = rBIOS.loadObjectAt (aDouble, nAddr);
302     if (eErrCode != store_E_None)
303         return eErrCode;
304 
305     // Read double indirect and leave.
306     return aDouble.read (nDouble, nSingle, rData, rBIOS);
307 }
308 
309 /*
310  * write (single indirect).
311  */
312 storeError OStoreIndirectionPageObject::write (
313     sal_uInt16             nSingle,
314     OStoreDataPageObject  &rData,
315     OStorePageBIOS        &rBIOS)
316 {
317     PageHolderObject< page > xImpl (m_xPage);
318     page & rPage = (*xImpl);
319 
320     // Check arguments.
321     sal_uInt16 const nLimit = rPage.capacityCount();
322     if (!(nSingle < nLimit))
323         return store_E_InvalidAccess;
324 
325     // Obtain data page location.
326     sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[nSingle]);
327     if (nAddr == STORE_PAGE_NULL)
328     {
329         // Allocate data page.
330         storeError eErrCode = rBIOS.allocate (rData);
331         if (eErrCode != store_E_None)
332             return eErrCode;
333 
334         // Store data page location.
335         rPage.m_pData[nSingle] = store::htonl(rData.location());
336 
337         // Save this page.
338         return rBIOS.saveObjectAt (*this, location());
339     }
340     else
341     {
342         // Save data page.
343         return rBIOS.saveObjectAt (rData, nAddr);
344     }
345 }
346 
347 /*
348  * write (double indirect).
349  */
350 storeError OStoreIndirectionPageObject::write (
351     sal_uInt16             nDouble,
352     sal_uInt16             nSingle,
353     OStoreDataPageObject  &rData,
354     OStorePageBIOS        &rBIOS)
355 {
356     PageHolderObject< page > xImpl (m_xPage);
357     page & rPage = (*xImpl);
358 
359     // Check arguments.
360     sal_uInt16 const nLimit = rPage.capacityCount();
361     if (!((nDouble < nLimit) && (nSingle < nLimit)))
362         return store_E_InvalidAccess;
363 
364     // Load or create single indirect page.
365     OStoreIndirectionPageObject aSingle;
366     storeError eErrCode = aSingle.loadOrCreate (store::ntohl(rPage.m_pData[nDouble]), rBIOS);
367     if (eErrCode != store_E_None)
368     {
369         if (eErrCode != store_E_Pending)
370             return eErrCode;
371         rPage.m_pData[nDouble] = store::htonl(aSingle.location());
372 
373         eErrCode = rBIOS.saveObjectAt (*this, location());
374         if (eErrCode != store_E_None)
375             return eErrCode;
376     }
377 
378     // Write single indirect and leave.
379     return aSingle.write (nSingle, rData, rBIOS);
380 }
381 
382 /*
383  * write (triple indirect).
384  */
385 storeError OStoreIndirectionPageObject::write (
386     sal_uInt16             nTriple,
387     sal_uInt16             nDouble,
388     sal_uInt16             nSingle,
389     OStoreDataPageObject  &rData,
390     OStorePageBIOS        &rBIOS)
391 {
392     PageHolderObject< page > xImpl (m_xPage);
393     page & rPage = (*xImpl);
394 
395     // Check arguments.
396     sal_uInt16 const nLimit = rPage.capacityCount();
397     if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit)))
398         return store_E_InvalidAccess;
399 
400     // Load or create double indirect page.
401     OStoreIndirectionPageObject aDouble;
402     storeError eErrCode = aDouble.loadOrCreate (store::ntohl(rPage.m_pData[nTriple]), rBIOS);
403     if (eErrCode != store_E_None)
404     {
405         if (eErrCode != store_E_Pending)
406             return eErrCode;
407         rPage.m_pData[nTriple] = store::htonl(aDouble.location());
408 
409         eErrCode = rBIOS.saveObjectAt (*this, location());
410         if (eErrCode != store_E_None)
411             return eErrCode;
412     }
413 
414     // Write double indirect and leave.
415     return aDouble.write (nDouble, nSingle, rData, rBIOS);
416 }
417 
418 /*
419  * truncate (single indirect).
420  */
421 storeError OStoreIndirectionPageObject::truncate (
422     sal_uInt16       nSingle,
423     OStorePageBIOS & rBIOS)
424 {
425     PageHolderObject< page > xImpl (m_xPage);
426     page & rPage = (*xImpl);
427 
428     // Check arguments.
429     sal_uInt16 const nLimit = rPage.capacityCount();
430     if (!(nSingle < nLimit))
431         return store_E_InvalidAccess;
432 
433     // Truncate.
434     storeError eErrCode = store_E_None;
435     for (sal_uInt16 i = nLimit; i > nSingle; i--)
436     {
437         // Obtain data page location.
438         sal_uInt32 const nAddr = store::ntohl(rPage.m_pData[i - 1]);
439         if (nAddr != STORE_PAGE_NULL)
440         {
441             // Free data page.
442             eErrCode = rBIOS.free (nAddr);
443             if (eErrCode != store_E_None)
444                 return eErrCode;
445 
446             // Clear pointer to data page.
447             rPage.m_pData[i - 1] = STORE_PAGE_NULL;
448             touch();
449         }
450     }
451 
452     // Check for modified page.
453     if (dirty())
454     {
455         // Save this page.
456         eErrCode = rBIOS.saveObjectAt (*this, location());
457     }
458 
459     // Done.
460     return eErrCode;
461 }
462 
463 /*
464  * truncate (double indirect).
465  */
466 storeError OStoreIndirectionPageObject::truncate (
467     sal_uInt16             nDouble,
468     sal_uInt16             nSingle,
469     OStorePageBIOS        &rBIOS)
470 {
471     PageHolderObject< page > xImpl (m_xPage);
472     page & rPage = (*xImpl);
473 
474     // Check arguments.
475     sal_uInt16 const nLimit = rPage.capacityCount();
476     if (!((nDouble < nLimit) && (nSingle < nLimit)))
477         return store_E_InvalidAccess;
478 
479     // Truncate.
480     storeError eErrCode = store_E_None;
481     for (sal_uInt16 i = nLimit; i > nDouble + 1; i--)
482     {
483         // Truncate single indirect page to zero direct pages.
484         eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, rBIOS);
485         if (eErrCode != store_E_None)
486             return eErrCode;
487 
488         // Clear pointer to single indirect page.
489         rPage.m_pData[i - 1] = STORE_PAGE_NULL;
490         touch();
491     }
492 
493     // Truncate last single indirect page to 'nSingle' direct pages.
494     eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nDouble]), nSingle, rBIOS);
495     if (eErrCode != store_E_None)
496         return eErrCode;
497 
498     // Check for complete truncation.
499     if (nSingle == 0)
500     {
501         // Clear pointer to last single indirect page.
502         rPage.m_pData[nDouble] = STORE_PAGE_NULL;
503         touch();
504     }
505 
506     // Check for modified page.
507     if (dirty())
508     {
509         // Save this page.
510         eErrCode = rBIOS.saveObjectAt (*this, location());
511     }
512 
513     // Done.
514     return eErrCode;
515 }
516 
517 /*
518  * truncate (triple indirect).
519  */
520 storeError OStoreIndirectionPageObject::truncate (
521     sal_uInt16             nTriple,
522     sal_uInt16             nDouble,
523     sal_uInt16             nSingle,
524     OStorePageBIOS        &rBIOS)
525 {
526     PageHolderObject< page > xImpl (m_xPage);
527     page & rPage = (*xImpl);
528 
529     // Check arguments.
530     sal_uInt16 const nLimit = rPage.capacityCount();
531     if (!((nTriple < nLimit) && (nDouble < nLimit) && (nSingle < nLimit)))
532         return store_E_InvalidAccess;
533 
534     // Truncate.
535     storeError eErrCode = store_E_None;
536     for (sal_uInt16 i = nLimit; i > nTriple + 1; i--)
537     {
538         // Truncate double indirect page to zero single indirect pages.
539         eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[i - 1]), 0, 0, rBIOS);
540         if (eErrCode != store_E_None)
541             return eErrCode;
542 
543         // Clear pointer to double indirect page.
544         rPage.m_pData[i - 1] = STORE_PAGE_NULL;
545         touch();
546     }
547 
548     // Truncate last double indirect page to 'nDouble', 'nSingle' pages.
549     eErrCode = store_truncate_Impl (store::ntohl(rPage.m_pData[nTriple]), nDouble, nSingle, rBIOS);
550     if (eErrCode != store_E_None)
551         return eErrCode;
552 
553     // Check for complete truncation.
554     if ((nDouble + nSingle) == 0)
555     {
556         // Clear pointer to last double indirect page.
557         rPage.m_pData[nTriple] = STORE_PAGE_NULL;
558         touch();
559     }
560 
561     // Check for modified page.
562     if (dirty())
563     {
564         // Save this page.
565         eErrCode = rBIOS.saveObjectAt (*this, location());
566     }
567 
568     // Done.
569     return eErrCode;
570 }
571 
572 /*========================================================================
573  *
574  * OStoreDirectoryPageObject implementation.
575  *
576  *======================================================================*/
577 /*
578  * guard.
579  */
580 storeError OStoreDirectoryPageObject::guard (sal_uInt32 nAddr)
581 {
582     return PageHolderObject< page >::guard (m_xPage, nAddr);
583 }
584 
585 /*
586  * verify.
587  */
588 storeError OStoreDirectoryPageObject::verify (sal_uInt32 nAddr) const
589 {
590     return PageHolderObject< page >::verify (m_xPage, nAddr);
591     // OLD: m_rPage.verifyVersion (STORE_MAGIC_DIRECTORYPAGE);
592 }
593 
594 /*
595  * scope (external data page; private).
596  */
597 OStoreDirectoryPageData::ChunkScope
598 OStoreDirectoryPageObject::scope (
599     sal_uInt32                       nPage,
600     page::DataBlock::LinkDescriptor &rDescr) const
601 {
602     page const & rPage = PAGE();
603     OStoreDirectoryDataBlock const & rDataBlock = rPage.m_aDataBlock;
604 
605     sal_uInt32 index0, index1, index2, index3;
606 
607     // direct.
608     sal_uInt32 nCount = rDataBlock.directCount();
609     sal_uInt32 nLimit = nCount;
610     if (nPage < nLimit)
611     {
612         // Page to index reduction.
613         index0 = nPage;
614 
615         // Setup LinkDescriptor indices.
616         rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
617 
618         // Done.
619         return page::SCOPE_DIRECT;
620     }
621     nPage -= nLimit;
622 
623     // single indirect.
624     sal_uInt32 const nCapacity = indirect::capacityCount(rPage.m_aDescr);
625     nCount = rDataBlock.singleCount();
626     nLimit = nCount * nCapacity;
627     if (nPage < nLimit)
628     {
629         // Page to index reduction.
630         sal_uInt32 n = nPage;
631 
632         // Reduce to single indirect i(1), direct n = i(0).
633         index1 = n / nCapacity;
634         index0 = n % nCapacity;
635 
636         // Verify reduction.
637         n = index1 * nCapacity + index0;
638         OSL_POSTCOND(n == nPage, "wrong math on indirect indices");
639         if (n != nPage)
640             return page::SCOPE_UNKNOWN;
641 
642         // Setup LinkDescriptor indices.
643         rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
644         rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff);
645 
646         // Done.
647         return page::SCOPE_SINGLE;
648     }
649     nPage -= nLimit;
650 
651     // double indirect.
652     nCount = rDataBlock.doubleCount();
653     nLimit = nCount * nCapacity * nCapacity;
654     if (nPage < nLimit)
655     {
656         // Page to index reduction.
657         sal_uInt32 n = nPage;
658 
659         // Reduce to double indirect i(2), single indirect n = i(0).
660         index2 = n / (nCapacity * nCapacity);
661         n      = n % (nCapacity * nCapacity);
662 
663         // Reduce to single indirect i(1), direct n = i(0).
664         index1 = n / nCapacity;
665         index0 = n % nCapacity;
666 
667         // Verify reduction.
668         n = index2 * nCapacity * nCapacity +
669             index1 * nCapacity + index0;
670         OSL_POSTCOND(n == nPage, "wrong math on double indirect indices");
671         if (n != nPage)
672             return page::SCOPE_UNKNOWN;
673 
674         // Setup LinkDescriptor indices.
675         rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
676         rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff);
677         rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff);
678 
679         // Done.
680         return page::SCOPE_DOUBLE;
681     }
682     nPage -= nLimit;
683 
684     // triple indirect.
685     nCount = rDataBlock.tripleCount();
686     nLimit = nCount * nCapacity * nCapacity * nCapacity;
687     if (nPage < nLimit)
688     {
689         // Page to index reduction.
690         sal_uInt32 n = nPage;
691 
692         // Reduce to triple indirect i(3), double indirect n.
693         index3 = n / (nCapacity * nCapacity * nCapacity);
694         n      = n % (nCapacity * nCapacity * nCapacity);
695 
696         // Reduce to double indirect i(2), single indirect n.
697         index2 = n / (nCapacity * nCapacity);
698         n      = n % (nCapacity * nCapacity);
699 
700         // Reduce to single indirect i(1), direct n = i(0).
701         index1 = n / nCapacity;
702         index0 = n % nCapacity;
703 
704         // Verify reduction.
705         n = index3 * nCapacity * nCapacity * nCapacity +
706             index2 * nCapacity * nCapacity +
707             index1 * nCapacity + index0;
708         OSL_POSTCOND(n == nPage, "wrong math on triple indirect indices");
709         if (n != nPage)
710             return page::SCOPE_UNKNOWN;
711 
712         // Setup LinkDescriptor indices.
713         rDescr.m_nIndex0 = (sal_uInt16)(index0 & 0xffff);
714         rDescr.m_nIndex1 = (sal_uInt16)(index1 & 0xffff);
715         rDescr.m_nIndex2 = (sal_uInt16)(index2 & 0xffff);
716         rDescr.m_nIndex3 = (sal_uInt16)(index3 & 0xffff);
717 
718         // Done.
719         return page::SCOPE_TRIPLE;
720     }
721 
722     // Unreachable (more than triple indirect).
723     return page::SCOPE_UNREACHABLE;
724 }
725 
726 #if 0  /* NYI */
727 /*
728  * chunk (external data page).
729  */
730 inode::ChunkDescriptor OStoreDirectoryPageObject::chunk (sal_uInt32 nOffset)
731 {
732     // @@@ INSUFFICIENT: NEED SCOPE AS WELL @@@
733     sal_uInt32 nCapacity = m_rPage.capacity();
734     if (nOffset < nCapacity)
735         // Internal scope (inode page).
736         return inode::ChunkDescriptor (nOffset, nCapacity);
737     else
738         // External scope (data page).
739         return inode::ChunkDescriptor (nOffset - nCapacity, data::capacity(m_rPage.m_aDescr));
740 
741     inode::ChunkScope eScope = m_rPage.scope(nOffset);
742     if (eScope == inode::SCOPE_INTERNAL)
743         // Inode page (internal scope).
744         return inode::ChunkDescriptor (nOffset, m_rPage.capacity());
745     else
746         // Data page (external scope).
747         return inode::ChunkDescriptor (nOffset - m_rPage.capacity(), data::capacity(m_rPage.m_aDescr));
748 }
749 #endif /* NYI */
750 
751 /*
752  * read (external data page).
753  */
754 storeError OStoreDirectoryPageObject::read (
755     sal_uInt32             nPage,
756     OStoreDataPageObject  &rData,
757     OStorePageBIOS        &rBIOS)
758 {
759     // Determine scope and link indices.
760     page::DataBlock::LinkDescriptor aLink;
761     page::ChunkScope eScope = scope (nPage, aLink);
762 
763     storeError eErrCode = store_E_None;
764     if (eScope == page::SCOPE_DIRECT)
765     {
766         sal_uInt32 const nAddr = directLink (aLink.m_nIndex0);
767         if (nAddr == STORE_PAGE_NULL)
768             return store_E_NotExists;
769 
770         eErrCode = rBIOS.loadObjectAt (rData, nAddr);
771     }
772     else if (eScope == page::SCOPE_SINGLE)
773     {
774         sal_uInt32 const nAddr = singleLink (aLink.m_nIndex1);
775         if (nAddr == STORE_PAGE_NULL)
776             return store_E_NotExists;
777 
778         OStoreIndirectionPageObject aSingle;
779         eErrCode = rBIOS.loadObjectAt (aSingle, nAddr);
780         if (eErrCode != store_E_None)
781             return eErrCode;
782 
783         eErrCode = aSingle.read (aLink.m_nIndex0, rData, rBIOS);
784     }
785     else if (eScope == page::SCOPE_DOUBLE)
786     {
787         sal_uInt32 const nAddr = doubleLink (aLink.m_nIndex2);
788         if (nAddr == STORE_PAGE_NULL)
789             return store_E_NotExists;
790 
791         OStoreIndirectionPageObject aDouble;
792         eErrCode = rBIOS.loadObjectAt (aDouble, nAddr);
793         if (eErrCode != store_E_None)
794             return eErrCode;
795 
796         eErrCode = aDouble.read (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
797     }
798     else if (eScope == page::SCOPE_TRIPLE)
799     {
800         sal_uInt32 const nAddr = tripleLink (aLink.m_nIndex3);
801         if (nAddr == STORE_PAGE_NULL)
802             return store_E_NotExists;
803 
804         OStoreIndirectionPageObject aTriple;
805         eErrCode = rBIOS.loadObjectAt (aTriple, nAddr);
806         if (eErrCode != store_E_None)
807             return eErrCode;
808 
809         eErrCode = aTriple.read (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
810     }
811     else if (eScope == page::SCOPE_UNREACHABLE)
812     {
813         // Out of scope.
814         eErrCode = store_E_CantSeek;
815     }
816     else
817     {
818         // Unknown scope.
819         OSL_TRACE("OStoreDirectoryPageObject::get(): scope failed");
820         eErrCode = store_E_Unknown;
821     }
822 
823     // Leave.
824     return eErrCode;
825 }
826 
827 /*
828  * write (external data page).
829  */
830 storeError OStoreDirectoryPageObject::write (
831     sal_uInt32             nPage,
832     OStoreDataPageObject  &rData,
833     OStorePageBIOS        &rBIOS)
834 {
835     // Determine scope and link indices.
836     page::DataBlock::LinkDescriptor aLink;
837     page::ChunkScope eScope = scope (nPage, aLink);
838 
839     storeError eErrCode = store_E_None;
840     if (eScope == page::SCOPE_DIRECT)
841     {
842         sal_uInt32 const nAddr = directLink (aLink.m_nIndex0);
843         if (nAddr == STORE_PAGE_NULL)
844         {
845             // Allocate data page.
846             eErrCode = rBIOS.allocate (rData);
847             if (eErrCode != store_E_None)
848                 return eErrCode;
849 
850             // Store data page location.
851             directLink (aLink.m_nIndex0, rData.location());
852         }
853         else
854         {
855             // Save data page.
856             eErrCode = rBIOS.saveObjectAt (rData, nAddr);
857         }
858     }
859     else if (eScope == page::SCOPE_SINGLE)
860     {
861         OStoreIndirectionPageObject aSingle;
862         eErrCode = aSingle.loadOrCreate (singleLink (aLink.m_nIndex1), rBIOS);
863         if (eErrCode != store_E_None)
864         {
865             if (eErrCode != store_E_Pending)
866                 return eErrCode;
867             singleLink (aLink.m_nIndex1, aSingle.location());
868         }
869 
870         eErrCode = aSingle.write (aLink.m_nIndex0, rData, rBIOS);
871     }
872     else if (eScope == page::SCOPE_DOUBLE)
873     {
874         OStoreIndirectionPageObject aDouble;
875         eErrCode = aDouble.loadOrCreate (doubleLink (aLink.m_nIndex2), rBIOS);
876         if (eErrCode != store_E_None)
877         {
878             if (eErrCode != store_E_Pending)
879                 return eErrCode;
880             doubleLink (aLink.m_nIndex2, aDouble.location());
881         }
882 
883         eErrCode = aDouble.write (aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
884     }
885     else if (eScope == page::SCOPE_TRIPLE)
886     {
887         OStoreIndirectionPageObject aTriple;
888         eErrCode = aTriple.loadOrCreate (tripleLink (aLink.m_nIndex3), rBIOS);
889         if (eErrCode != store_E_None)
890         {
891             if (eErrCode != store_E_Pending)
892                 return eErrCode;
893             tripleLink (aLink.m_nIndex3, aTriple.location());
894         }
895 
896         eErrCode = aTriple.write (aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rData, rBIOS);
897     }
898     else if (eScope == page::SCOPE_UNREACHABLE)
899     {
900         // Out of scope.
901         eErrCode = store_E_CantSeek;
902     }
903     else
904     {
905         // Unknown scope.
906         OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed");
907         eErrCode = store_E_Unknown;
908     }
909 
910     // Leave.
911     return eErrCode;
912 }
913 
914 /*
915  * truncate (external data page).
916  */
917 storeError OStoreDirectoryPageObject::truncate (
918     sal_uInt32             nPage,
919     OStorePageBIOS        &rBIOS)
920 {
921     // Determine scope and link indices.
922     page::DataBlock::LinkDescriptor aLink;
923     page::ChunkScope eScope = scope (nPage, aLink);
924 
925     storeError eErrCode = store_E_None;
926     if (eScope == page::SCOPE_DIRECT)
927     {
928         // Truncate all triple indirect pages.
929         eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS);
930         if (eErrCode != store_E_None)
931             return eErrCode;
932 
933         // Truncate all double indirect pages.
934         eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS);
935         if (eErrCode != store_E_None)
936             return eErrCode;
937 
938         // Truncate all single indirect pages.
939         eErrCode = truncate (page::SCOPE_SINGLE, 0, rBIOS);
940         if (eErrCode != store_E_None)
941             return eErrCode;
942 
943         // Truncate direct pages, including 'aLink.m_nIndex0'.
944         eErrCode = truncate (eScope, aLink.m_nIndex0, rBIOS);
945     }
946     else if (eScope == page::SCOPE_SINGLE)
947     {
948         // Truncate all triple indirect pages.
949         eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS);
950         if (eErrCode != store_E_None)
951             return eErrCode;
952 
953         // Truncate all double indirect pages.
954         eErrCode = truncate (page::SCOPE_DOUBLE, 0, rBIOS);
955         if (eErrCode != store_E_None)
956             return eErrCode;
957 
958         // Truncate single indirect pages, downto 'aLink.m_nIndex1'.
959         eErrCode = truncate (eScope, aLink.m_nIndex1 + 1, rBIOS);
960         if (eErrCode != store_E_None)
961             return eErrCode;
962 
963         // Truncate last single indirect page to ... pages.
964         eErrCode = store_truncate_Impl (singleLink (aLink.m_nIndex1), aLink.m_nIndex0, rBIOS);
965         if (eErrCode != store_E_None)
966             return eErrCode;
967 
968         // Check for complete truncation.
969         if (aLink.m_nIndex0 == 0)
970         {
971             // Clear pointer to last single indirect page.
972             singleLink (aLink.m_nIndex1, STORE_PAGE_NULL);
973         }
974     }
975     else if (eScope == page::SCOPE_DOUBLE)
976     {
977         // Truncate all triple indirect pages.
978         eErrCode = truncate (page::SCOPE_TRIPLE, 0, rBIOS);
979         if (eErrCode != store_E_None)
980             return eErrCode;
981 
982         // Truncate double indirect pages, downto 'aLink.m_nIndex2'.
983         eErrCode = truncate (eScope, aLink.m_nIndex2 + 1, rBIOS);
984         if (eErrCode != store_E_None)
985             return eErrCode;
986 
987         // Truncate last double indirect page to ... pages.
988         eErrCode = store_truncate_Impl (
989             doubleLink (aLink.m_nIndex2), aLink.m_nIndex1, aLink.m_nIndex0, rBIOS);
990         if (eErrCode != store_E_None)
991             return eErrCode;
992 
993         // Check for complete truncation.
994         if ((aLink.m_nIndex1 + aLink.m_nIndex0) == 0)
995         {
996             // Clear pointer to last double indirect page.
997             doubleLink (aLink.m_nIndex2, STORE_PAGE_NULL);
998         }
999     }
1000     else if (eScope == page::SCOPE_TRIPLE)
1001     {
1002         // Truncate triple indirect pages, downto 'aLink.m_nIndex3'.
1003         eErrCode = truncate (eScope, aLink.m_nIndex3 + 1, rBIOS);
1004         if (eErrCode != store_E_None)
1005             return eErrCode;
1006 
1007         // Truncate last triple indirect page to ... pages.
1008         eErrCode = store_truncate_Impl (
1009             tripleLink (aLink.m_nIndex3), aLink.m_nIndex2, aLink.m_nIndex1, aLink.m_nIndex0, rBIOS);
1010         if (eErrCode != store_E_None)
1011             return eErrCode;
1012 
1013         // Check for complete truncation.
1014         if ((aLink.m_nIndex2 + aLink.m_nIndex1 + aLink.m_nIndex0) == 0)
1015         {
1016             // Clear pointer to last triple indirect page.
1017             tripleLink (aLink.m_nIndex3, STORE_PAGE_NULL);
1018         }
1019     }
1020     else if (eScope == page::SCOPE_UNREACHABLE)
1021     {
1022         // Out of scope.
1023         eErrCode = store_E_CantSeek;
1024     }
1025     else
1026     {
1027         // Unknown scope.
1028         OSL_TRACE("OStoreDirectoryPageObject::put(): scope failed");
1029         eErrCode = store_E_Unknown;
1030     }
1031 
1032     // Leave.
1033     return eErrCode;
1034 }
1035 
1036 /*
1037  * truncate (external data page scope; private).
1038  */
1039 storeError OStoreDirectoryPageObject::truncate (
1040     page::ChunkScope       eScope,
1041     sal_uInt16             nRemain,
1042     OStorePageBIOS        &rBIOS)
1043 {
1044     OStoreDirectoryDataBlock const & rDataBlock = PAGE().m_aDataBlock;
1045 
1046     // Enter.
1047     storeError eErrCode = store_E_None;
1048     if (eScope == page::SCOPE_DIRECT)
1049     {
1050         // Truncate direct data pages.
1051         sal_uInt16 i, n = rDataBlock.directCount();
1052         for (i = n; i > nRemain; i--)
1053         {
1054             // Obtain data page location.
1055             sal_uInt32 nAddr = directLink (i - 1);
1056             if (nAddr == STORE_PAGE_NULL) continue;
1057 
1058             // Free data page.
1059             eErrCode = rBIOS.free (nAddr);
1060             if (eErrCode != store_E_None)
1061                 break;
1062 
1063             // Clear pointer to data page.
1064             directLink (i - 1, STORE_PAGE_NULL);
1065         }
1066 
1067         // Done.
1068         return eErrCode;
1069     }
1070 
1071     if (eScope == page::SCOPE_SINGLE)
1072     {
1073         // Truncate single indirect pages.
1074         sal_uInt16 i, n = rDataBlock.singleCount();
1075         for (i = n; i > nRemain; i--)
1076         {
1077             // Truncate single indirect page to zero data pages.
1078             eErrCode = store_truncate_Impl (singleLink (i - 1), 0, rBIOS);
1079             if (eErrCode != store_E_None)
1080                 break;
1081 
1082             // Clear pointer to single indirect page.
1083             singleLink (i - 1, STORE_PAGE_NULL);
1084         }
1085 
1086         // Done.
1087         return eErrCode;
1088     }
1089 
1090     if (eScope == page::SCOPE_DOUBLE)
1091     {
1092         // Truncate double indirect pages.
1093         sal_uInt16 i, n = rDataBlock.doubleCount();
1094         for (i = n; i > nRemain; i--)
1095         {
1096             // Truncate double indirect page to zero single indirect pages.
1097             eErrCode = store_truncate_Impl (doubleLink (i - 1), 0, 0, rBIOS);
1098             if (eErrCode != store_E_None)
1099                 break;
1100 
1101             // Clear pointer to double indirect page.
1102             doubleLink (i - 1, STORE_PAGE_NULL);
1103         }
1104 
1105         // Done.
1106         return eErrCode;
1107     }
1108 
1109     if (eScope == page::SCOPE_TRIPLE)
1110     {
1111         // Truncate triple indirect pages.
1112         sal_uInt16 i, n = rDataBlock.tripleCount();
1113         for (i = n; i > nRemain; i--)
1114         {
1115             // Truncate to zero double indirect pages.
1116             eErrCode = store_truncate_Impl (tripleLink (i - 1), 0, 0, 0, rBIOS);
1117             if (eErrCode != store_E_None)
1118                 break;
1119 
1120             // Clear pointer to triple indirect page.
1121             tripleLink (i - 1, STORE_PAGE_NULL);
1122         }
1123 
1124         // Done.
1125         return eErrCode;
1126     }
1127 
1128     // Invalid scope.
1129     return store_E_InvalidAccess;
1130 }
1131