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