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