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