Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "storpage.hxx"
21 :
22 : #include "sal/types.h"
23 : #include "rtl/string.h"
24 : #include "rtl/ref.hxx"
25 : #include "osl/diagnose.h"
26 : #include "osl/mutex.hxx"
27 :
28 : #include "store/types.h"
29 :
30 : #include "object.hxx"
31 : #include "lockbyte.hxx"
32 :
33 : #include "storbase.hxx"
34 : #include "stordata.hxx"
35 : #include "stortree.hxx"
36 :
37 : using namespace store;
38 :
39 : /*========================================================================
40 : *
41 : * OStorePageManager implementation.
42 : *
43 : *======================================================================*/
44 : const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
45 :
46 : /*
47 : * OStorePageManager.
48 : */
49 0 : OStorePageManager::OStorePageManager (void)
50 : {
51 0 : }
52 :
53 : /*
54 : * ~OStorePageManager.
55 : */
56 0 : OStorePageManager::~OStorePageManager (void)
57 : {
58 0 : }
59 :
60 : /*
61 : * isKindOf.
62 : */
63 0 : bool OStorePageManager::isKindOf (sal_uInt32 nTypeId)
64 : {
65 0 : return (nTypeId == m_nTypeId);
66 : }
67 :
68 : /*
69 : * initialize (two-phase construction).
70 : * Precond: none.
71 : */
72 0 : storeError OStorePageManager::initialize (
73 : ILockBytes * pLockBytes,
74 : storeAccessMode eAccessMode,
75 : sal_uInt16 & rnPageSize)
76 : {
77 : // Acquire exclusive access.
78 0 : osl::MutexGuard aGuard(*this);
79 :
80 : // Check arguments.
81 0 : if (!pLockBytes)
82 0 : return store_E_InvalidParameter;
83 :
84 : // Initialize base.
85 0 : storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
86 0 : if (eErrCode != store_E_None)
87 0 : return eErrCode;
88 :
89 : // Check for (not) writeable.
90 0 : if (!base::isWriteable())
91 : {
92 : // Readonly. Load RootNode.
93 0 : return base::loadObjectAt (m_aRoot, rnPageSize);
94 : }
95 :
96 : // Writeable. Load or Create RootNode.
97 0 : eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
98 0 : if (eErrCode == store_E_Pending)
99 : {
100 : // Creation notification.
101 0 : PageHolderObject< page > xRoot (m_aRoot.get());
102 :
103 : // Pre-allocate left most entry (ugly, but we can't insert to left).
104 0 : OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
105 0 : xRoot->insert (0, entry(aKey));
106 :
107 : // Save RootNode.
108 0 : eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
109 : }
110 :
111 : // Done.
112 0 : return eErrCode;
113 : }
114 :
115 : /*
116 : * find_lookup (w/o split()).
117 : * Internal: Precond: initialized, readable, exclusive access.
118 : */
119 0 : storeError OStorePageManager::find_lookup (
120 : OStoreBTreeNodeObject & rNode,
121 : sal_uInt16 & rIndex,
122 : OStorePageKey const & rKey)
123 : {
124 : // Find Node and Index.
125 0 : storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
126 0 : if (eErrCode != store_E_None)
127 0 : return eErrCode;
128 :
129 : // Greater or Equal.
130 0 : PageHolderObject< page > xPage (rNode.get());
131 : OSL_POSTCOND(rIndex < xPage->usageCount(), "store::PageManager::find_lookup(): logic error");
132 0 : entry e (xPage->m_pData[rIndex]);
133 :
134 : // Check for exact match.
135 0 : if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
136 : {
137 : // Page not present.
138 0 : return store_E_NotExists;
139 : }
140 :
141 : // Check address.
142 0 : if (e.m_aLink.location() == STORE_PAGE_NULL)
143 : {
144 : // Page not present.
145 0 : return store_E_NotExists;
146 : }
147 :
148 0 : return store_E_None;
149 : }
150 :
151 : /*
152 : * remove_Impl (possibly down from root).
153 : * Internal: Precond: initialized, writeable, exclusive access.
154 : */
155 :
156 0 : storeError OStorePageManager::remove_Impl (entry & rEntry)
157 : {
158 0 : OStoreBTreeNodeObject aNode (m_aRoot.get());
159 :
160 : // Check current page index.
161 0 : PageHolderObject< page > xPage (aNode.get());
162 0 : sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
163 0 : if (!(i < n))
164 : {
165 : // Path to entry not exists (Must not happen(?)).
166 0 : return store_E_NotExists;
167 : }
168 :
169 : // Compare entry.
170 0 : entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
171 :
172 : // Iterate down until equal match.
173 0 : while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
174 : {
175 : // Check link address.
176 0 : sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
177 0 : if (nAddr == STORE_PAGE_NULL)
178 : {
179 : // Path to entry not exists (Must not happen(?)).
180 0 : return store_E_NotExists;
181 : }
182 :
183 : // Load link page.
184 0 : storeError eErrCode = loadObjectAt (aNode, nAddr);
185 0 : if (eErrCode != store_E_None)
186 0 : return eErrCode;
187 :
188 0 : PageHolderObject< page > xNext (aNode.get());
189 0 : xNext.swap (xPage);
190 :
191 : // Check index.
192 0 : i = xPage->find (rEntry), n = xPage->usageCount();
193 0 : if (!(i < n))
194 : {
195 : // Path to entry not exists (Must not happen(?)).
196 0 : return store_E_NotExists;
197 : }
198 :
199 : // Compare entry.
200 0 : result = rEntry.compare (xPage->m_pData[i]);
201 0 : }
202 :
203 : OSL_POSTCOND(
204 : result != entry::COMPARE_LESS,
205 : "OStorePageManager::remove(): find failed");
206 :
207 : // Check entry comparison.
208 0 : if (result == entry::COMPARE_LESS)
209 : {
210 : // Must not happen.
211 0 : return store_E_Unknown;
212 : }
213 :
214 : // Remove down from current page (recursive).
215 0 : return aNode.remove (i, rEntry, *this);
216 : }
217 :
218 : /*
219 : * namei.
220 : * Precond: none (static).
221 : */
222 0 : storeError OStorePageManager::namei (
223 : const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
224 : {
225 : // Check parameter.
226 0 : if (!(pPath && pName))
227 0 : return store_E_InvalidParameter;
228 :
229 : // Check name length.
230 0 : if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
231 0 : return store_E_NameTooLong;
232 :
233 : // Transform pathname into key.
234 0 : rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
235 0 : rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
236 :
237 : // Done.
238 0 : return store_E_None;
239 : }
240 :
241 : /*
242 : * iget.
243 : * Precond: initialized.
244 : */
245 0 : storeError OStorePageManager::iget (
246 : OStoreDirectoryPageObject & rPage,
247 : sal_uInt32 nAttrib,
248 : const rtl_String * pPath,
249 : const rtl_String * pName,
250 : storeAccessMode eMode)
251 : {
252 : // Acquire exclusive access.
253 0 : osl::MutexGuard aGuard(*this);
254 :
255 : // Check precond.
256 0 : if (!self::isValid())
257 0 : return store_E_InvalidAccess;
258 :
259 : // Setup inode page key.
260 0 : OStorePageKey aKey;
261 0 : storeError eErrCode = namei (pPath, pName, aKey);
262 0 : if (eErrCode != store_E_None)
263 0 : return eErrCode;
264 :
265 : // Check for directory.
266 0 : if (nAttrib & STORE_ATTRIB_ISDIR)
267 : {
268 : // Ugly, but necessary (backward compatibility).
269 0 : aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
270 : }
271 :
272 : // Load inode page.
273 0 : eErrCode = load_dirpage_Impl (aKey, rPage);
274 0 : if (eErrCode != store_E_None)
275 : {
276 : // Check mode and reason.
277 0 : if (eErrCode != store_E_NotExists)
278 0 : return eErrCode;
279 :
280 0 : if (eMode == store_AccessReadWrite)
281 0 : return store_E_NotExists;
282 0 : if (eMode == store_AccessReadOnly)
283 0 : return store_E_NotExists;
284 :
285 0 : if (!base::isWriteable())
286 0 : return store_E_AccessViolation;
287 :
288 : // Create inode page.
289 0 : eErrCode = rPage.construct< inode >(base::allocator());
290 0 : if (eErrCode != store_E_None)
291 0 : return eErrCode;
292 :
293 : // Setup inode nameblock.
294 0 : PageHolderObject< inode > xPage (rPage.get());
295 :
296 0 : rPage.key (aKey);
297 0 : rPage.attrib (nAttrib);
298 :
299 : memcpy (
300 0 : &(xPage->m_aNameBlock.m_pData[0]),
301 0 : pName->buffer, pName->length);
302 :
303 : // Save inode page.
304 0 : eErrCode = save_dirpage_Impl (aKey, rPage);
305 0 : if (eErrCode != store_E_None)
306 0 : return eErrCode;
307 : }
308 :
309 : // Check for symbolic link.
310 0 : if (rPage.attrib() & STORE_ATTRIB_ISLINK)
311 : {
312 : // Obtain 'Destination' page key.
313 0 : PageHolderObject< inode > xPage (rPage.get());
314 0 : OStorePageKey aDstKey;
315 0 : memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
316 :
317 : // Load 'Destination' inode.
318 0 : eErrCode = load_dirpage_Impl (aDstKey, rPage);
319 0 : if (eErrCode != store_E_None)
320 0 : return eErrCode;
321 : }
322 :
323 : // Done.
324 0 : return store_E_None;
325 : }
326 :
327 : /*
328 : * iterate.
329 : * Precond: initialized.
330 : * ToDo: skip hardlink entries.
331 : */
332 0 : storeError OStorePageManager::iterate (
333 : OStorePageKey & rKey,
334 : OStorePageLink & rLink,
335 : sal_uInt32 & rAttrib)
336 : {
337 : // Acquire exclusive access.
338 0 : osl::MutexGuard aGuard(*this);
339 :
340 : // Check precond.
341 0 : if (!self::isValid())
342 0 : return store_E_InvalidAccess;
343 :
344 : // Find NodePage and Index.
345 0 : OStoreBTreeNodeObject aNode;
346 0 : sal_uInt16 i = 0;
347 0 : storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
348 0 : if (eErrCode != store_E_None)
349 0 : return eErrCode;
350 :
351 : // GreaterEqual. Found next entry.
352 0 : PageHolderObject< page > xNode (aNode.get());
353 0 : entry e (xNode->m_pData[i]);
354 :
355 : // Setup result.
356 0 : rKey = e.m_aKey;
357 0 : rLink = e.m_aLink;
358 0 : rAttrib = store::ntohl(e.m_nAttrib);
359 :
360 : // Done.
361 0 : return store_E_None;
362 : }
363 :
364 : /*
365 : * load => private: iget() @@@
366 : * Internal: Precond: initialized, exclusive access.
367 : */
368 0 : storeError OStorePageManager::load_dirpage_Impl (
369 : const OStorePageKey &rKey,
370 : OStoreDirectoryPageObject &rPage)
371 : {
372 : // Find Node and Index.
373 0 : OStoreBTreeNodeObject aNode;
374 0 : sal_uInt16 i = 0;
375 0 : storeError eErrCode = find_lookup (aNode, i, rKey);
376 0 : if (eErrCode != store_E_None)
377 0 : return eErrCode;
378 :
379 : // Existing entry. Load page.
380 0 : PageHolderObject< page > xNode (aNode.get());
381 0 : entry e (xNode->m_pData[i]);
382 0 : return loadObjectAt (rPage, e.m_aLink.location());
383 : }
384 :
385 : /*
386 : * save => private: iget(), rebuild() @@@
387 : * Internal: Precond: initialized, writeable, exclusive access.
388 : */
389 0 : storeError OStorePageManager::save_dirpage_Impl (
390 : const OStorePageKey &rKey,
391 : OStoreDirectoryPageObject &rPage)
392 : {
393 : // Find NodePage and Index.
394 0 : node aNode;
395 0 : sal_uInt16 i = 0;
396 :
397 0 : storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
398 0 : PageHolderObject< page > xNode (aNode.get());
399 0 : if (eErrCode != store_E_None)
400 : {
401 0 : if (eErrCode != store_E_AlreadyExists)
402 0 : return eErrCode;
403 :
404 : // Existing entry.
405 0 : entry e (xNode->m_pData[i]);
406 0 : if (e.m_aLink.location() != STORE_PAGE_NULL)
407 : {
408 : // Save page to existing location.
409 0 : return saveObjectAt (rPage, e.m_aLink.location());
410 : }
411 :
412 : // Allocate page.
413 0 : eErrCode = base::allocate (rPage);
414 0 : if (eErrCode != store_E_None)
415 0 : return eErrCode;
416 :
417 : // Update page location.
418 0 : xNode->m_pData[i].m_aLink = rPage.location();
419 :
420 : // Save modified NodePage.
421 0 : return saveObjectAt (aNode, aNode.location());
422 : }
423 :
424 : // Allocate page.
425 0 : eErrCode = base::allocate (rPage);
426 0 : if (eErrCode != store_E_None)
427 0 : return eErrCode;
428 :
429 : // Insert.
430 0 : OStorePageLink aLink (rPage.location());
431 0 : xNode->insert (i + 1, entry (rKey, aLink));
432 :
433 : // Save modified NodePage.
434 0 : return saveObjectAt (aNode, aNode.location());
435 : }
436 :
437 : /*
438 : * attrib [nAttrib = ((nAttrib & ~nMask1) | nMask2)].
439 : * Precond: initialized.
440 : */
441 0 : storeError OStorePageManager::attrib (
442 : const OStorePageKey &rKey,
443 : sal_uInt32 nMask1,
444 : sal_uInt32 nMask2,
445 : sal_uInt32 &rAttrib)
446 : {
447 : // Acquire exclusive access.
448 0 : osl::MutexGuard aGuard(*this);
449 :
450 : // Check precond.
451 0 : if (!self::isValid())
452 0 : return store_E_InvalidAccess;
453 :
454 : // Find NodePage and index.
455 0 : OStoreBTreeNodeObject aNode;
456 0 : sal_uInt16 i = 0;
457 0 : storeError eErrCode = find_lookup (aNode, i, rKey);
458 0 : if (eErrCode != store_E_None)
459 0 : return eErrCode;
460 :
461 : // Existing entry.
462 0 : PageHolderObject< page > xNode (aNode.get());
463 0 : entry e (xNode->m_pData[i]);
464 0 : if (nMask1 != nMask2)
465 : {
466 : // Evaluate new attributes.
467 0 : sal_uInt32 nAttrib = store::ntohl(e.m_nAttrib);
468 :
469 0 : nAttrib &= ~nMask1;
470 0 : nAttrib |= nMask2;
471 :
472 0 : if (store::htonl(nAttrib) != e.m_nAttrib)
473 : {
474 : // Check access mode.
475 0 : if (base::isWriteable())
476 : {
477 : // Set new attributes.
478 0 : e.m_nAttrib = store::htonl(nAttrib);
479 0 : xNode->m_pData[i] = e;
480 :
481 : // Save modified NodePage.
482 0 : eErrCode = saveObjectAt (aNode, aNode.location());
483 : }
484 : else
485 : {
486 : // Access denied.
487 0 : eErrCode = store_E_AccessViolation;
488 : }
489 : }
490 : }
491 :
492 : // Obtain current attributes.
493 0 : rAttrib = store::ntohl(e.m_nAttrib);
494 0 : return eErrCode;
495 : }
496 :
497 : /*
498 : * link (insert 'Source' as hardlink to 'Destination').
499 : * Precond: initialized, writeable.
500 : */
501 0 : storeError OStorePageManager::link (
502 : const OStorePageKey &rSrcKey,
503 : const OStorePageKey &rDstKey)
504 : {
505 : // Acquire exclusive access.
506 0 : osl::MutexGuard aGuard(*this);
507 :
508 : // Check precond.
509 0 : if (!self::isValid())
510 0 : return store_E_InvalidAccess;
511 :
512 0 : if (!base::isWriteable())
513 0 : return store_E_AccessViolation;
514 :
515 : // Find 'Destination' NodePage and Index.
516 0 : OStoreBTreeNodeObject aDstNode;
517 0 : sal_uInt16 i = 0;
518 0 : storeError eErrCode = find_lookup (aDstNode, i, rDstKey);
519 0 : if (eErrCode != store_E_None)
520 0 : return eErrCode;
521 :
522 : // Existing 'Destination' entry.
523 0 : PageHolderObject< page > xDstNode (aDstNode.get());
524 0 : entry e (xDstNode->m_pData[i]);
525 0 : OStorePageLink aDstLink (e.m_aLink);
526 :
527 : // Find 'Source' NodePage and Index.
528 0 : OStoreBTreeNodeObject aSrcNode;
529 0 : eErrCode = m_aRoot.find_insert (aSrcNode, i, rSrcKey, *this);
530 0 : if (eErrCode != store_E_None)
531 0 : return eErrCode;
532 :
533 : // Insert 'Source' entry.
534 0 : PageHolderObject< page > xSrcNode (aSrcNode.get());
535 0 : xSrcNode->insert (i + 1, entry (rSrcKey, aDstLink, STORE_ATTRIB_ISLINK));
536 0 : return saveObjectAt (aSrcNode, aSrcNode.location());
537 : }
538 :
539 : /*
540 : * symlink (insert 'Source' DirectoryPage as symlink to 'Destination').
541 : * Precond: initialized, writeable.
542 : */
543 0 : storeError OStorePageManager::symlink (
544 : const rtl_String *pSrcPath,
545 : const rtl_String *pSrcName,
546 : const OStorePageKey &rDstKey)
547 : {
548 : // Acquire exclusive access.
549 0 : osl::MutexGuard aGuard(*this);
550 :
551 : // Check precond.
552 0 : if (!self::isValid())
553 0 : return store_E_InvalidAccess;
554 :
555 0 : if (!base::isWriteable())
556 0 : return store_E_AccessViolation;
557 :
558 : // Check 'Source' parameter.
559 0 : storeError eErrCode = store_E_InvalidParameter;
560 0 : if (!(pSrcPath && pSrcName))
561 0 : return eErrCode;
562 :
563 : // Setup 'Source' page key.
564 0 : OStorePageKey aSrcKey;
565 0 : eErrCode = namei (pSrcPath, pSrcName, aSrcKey);
566 0 : if (eErrCode != store_E_None)
567 0 : return eErrCode;
568 :
569 : // Find 'Source' NodePage and Index.
570 0 : OStoreBTreeNodeObject aSrcNode;
571 0 : sal_uInt16 i = 0;
572 0 : eErrCode = m_aRoot.find_insert (aSrcNode, i, aSrcKey, *this);
573 0 : if (eErrCode != store_E_None)
574 0 : return eErrCode;
575 :
576 : // Initialize directory page.
577 0 : OStoreDirectoryPageObject aPage;
578 0 : eErrCode = aPage.construct< inode >(base::allocator());
579 0 : if (eErrCode != store_E_None)
580 0 : return eErrCode;
581 :
582 : // Setup as 'Source' directory page.
583 0 : inode_holder_type xNode (aPage.get());
584 0 : aPage.key (aSrcKey);
585 : memcpy (
586 0 : &(xNode->m_aNameBlock.m_pData[0]),
587 0 : pSrcName->buffer, pSrcName->length);
588 :
589 : // Store 'Destination' page key.
590 0 : OStorePageKey aDstKey (rDstKey);
591 0 : memcpy (&(xNode->m_pData[0]), &aDstKey, sizeof(aDstKey));
592 :
593 : // Mark 'Source' as symbolic link to 'Destination'.
594 0 : aPage.attrib (STORE_ATTRIB_ISLINK);
595 0 : aPage.dataLength (sal_uInt32(sizeof(aDstKey)));
596 :
597 : // Allocate and save 'Source' directory page.
598 0 : eErrCode = base::allocate (aPage);
599 0 : if (eErrCode != store_E_None)
600 0 : return eErrCode;
601 :
602 : // Insert 'Source' entry.
603 0 : PageHolderObject< page > xSrcNode (aSrcNode.get());
604 0 : OStorePageLink aSrcLink (aPage.location());
605 0 : xSrcNode->insert (i + 1, entry(aSrcKey, aSrcLink));
606 :
607 : // Save modified NodePage.
608 0 : return saveObjectAt (aSrcNode, aSrcNode.location());
609 : }
610 :
611 : /*
612 : * rename.
613 : * Precond: initialized, writeable.
614 : */
615 0 : storeError OStorePageManager::rename (
616 : const OStorePageKey &rSrcKey,
617 : const rtl_String *pDstPath,
618 : const rtl_String *pDstName)
619 : {
620 : // Acquire exclusive access.
621 0 : osl::MutexGuard aGuard(*this);
622 :
623 : // Check precond.
624 0 : if (!self::isValid())
625 0 : return store_E_InvalidAccess;
626 :
627 0 : if (!base::isWriteable())
628 0 : return store_E_AccessViolation;
629 :
630 : // Check 'Destination' parameter.
631 0 : storeError eErrCode = store_E_InvalidParameter;
632 0 : if (!(pDstPath && pDstName))
633 0 : return eErrCode;
634 :
635 : // Setup 'Destination' page key.
636 0 : OStorePageKey aDstKey;
637 0 : eErrCode = namei (pDstPath, pDstName, aDstKey);
638 0 : if (eErrCode != store_E_None)
639 0 : return eErrCode;
640 :
641 : // Find 'Source' NodePage and Index.
642 0 : OStoreBTreeNodeObject aSrcNode;
643 0 : sal_uInt16 i = 0;
644 0 : eErrCode = find_lookup (aSrcNode, i, rSrcKey);
645 0 : if (eErrCode != store_E_None)
646 0 : return eErrCode;
647 :
648 : // Existing 'Source' entry.
649 0 : PageHolderObject< page > xSrcNode (aSrcNode.get());
650 0 : entry e (xSrcNode->m_pData[i]);
651 :
652 : // Check for (not a) hardlink.
653 0 : OStoreDirectoryPageObject aPage;
654 0 : if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
655 : {
656 : // Load directory page.
657 0 : eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
658 0 : if (eErrCode != store_E_None)
659 0 : return eErrCode;
660 :
661 : // Check for directory.
662 0 : if (aPage.attrib() & STORE_ATTRIB_ISDIR)
663 : {
664 : // Ugly, but necessary (backward compatibility).
665 0 : aDstKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aDstKey.m_nLow), "/", 1));
666 : }
667 : }
668 :
669 : // Let 'Source' entry be 'Destination' entry.
670 0 : e.m_aKey = aDstKey;
671 :
672 : // Find 'Destination' NodePage and Index.
673 0 : OStoreBTreeNodeObject aDstNode;
674 0 : eErrCode = m_aRoot.find_insert (aDstNode, i, e.m_aKey, *this);
675 0 : if (eErrCode != store_E_None)
676 0 : return eErrCode;
677 :
678 : // Insert 'Destination' entry.
679 0 : PageHolderObject< page > xDstNode (aDstNode.get());
680 0 : xDstNode->insert (i + 1, e);
681 :
682 0 : eErrCode = saveObjectAt (aDstNode, aDstNode.location());
683 0 : if (eErrCode != store_E_None)
684 0 : return eErrCode;
685 :
686 : // Check for (not a) hardlink.
687 0 : if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
688 : {
689 : // Modify 'Source' directory page.
690 0 : inode_holder_type xNode (aPage.get());
691 :
692 : // Setup 'Destination' NameBlock.
693 0 : sal_Int32 nDstLen = pDstName->length;
694 : memcpy (
695 0 : &(xNode->m_aNameBlock.m_pData[0]),
696 0 : pDstName->buffer, pDstName->length);
697 : memset (
698 0 : &(xNode->m_aNameBlock.m_pData[nDstLen]),
699 0 : 0, STORE_MAXIMUM_NAMESIZE - nDstLen);
700 0 : aPage.key (e.m_aKey);
701 :
702 : // Save directory page.
703 0 : eErrCode = base::saveObjectAt (aPage, e.m_aLink.location());
704 0 : if (eErrCode != store_E_None)
705 0 : return eErrCode;
706 : }
707 :
708 : // Remove 'Source' entry.
709 0 : e.m_aKey = rSrcKey;
710 0 : return remove_Impl (e);
711 : }
712 :
713 : /*
714 : * remove.
715 : * Precond: initialized, writeable.
716 : */
717 0 : storeError OStorePageManager::remove (const OStorePageKey &rKey)
718 : {
719 : // Acquire exclusive access.
720 0 : osl::MutexGuard aGuard(*this);
721 :
722 : // Check precond.
723 0 : if (!self::isValid())
724 0 : return store_E_InvalidAccess;
725 :
726 0 : if (!base::isWriteable())
727 0 : return store_E_AccessViolation;
728 :
729 : // Find NodePage and index.
730 0 : OStoreBTreeNodeObject aNodePage;
731 0 : sal_uInt16 i = 0;
732 0 : storeError eErrCode = find_lookup (aNodePage, i, rKey);
733 0 : if (eErrCode != store_E_None)
734 0 : return eErrCode;
735 :
736 : // Existing entry.
737 0 : PageHolderObject< page > xNodePage (aNodePage.get());
738 0 : entry e (xNodePage->m_pData[i]);
739 :
740 : // Check for (not a) hardlink.
741 0 : if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
742 : {
743 : // Load directory page.
744 0 : OStoreDirectoryPageObject aPage;
745 0 : eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
746 0 : if (eErrCode != store_E_None)
747 0 : return eErrCode;
748 :
749 0 : inode_holder_type xNode (aPage.get());
750 :
751 : // Acquire page write access.
752 0 : OStorePageDescriptor aDescr (xNode->m_aDescr);
753 0 : eErrCode = base::acquirePage (aDescr, store_AccessReadWrite);
754 0 : if (eErrCode != store_E_None)
755 0 : return eErrCode;
756 :
757 : // Check for symbolic link.
758 0 : if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
759 : {
760 : // Ordinary inode. Determine 'Data' scope.
761 0 : inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
762 0 : if (eScope == inode::SCOPE_EXTERNAL)
763 : {
764 : // External 'Data' scope. Truncate all external data pages.
765 0 : eErrCode = aPage.truncate (0, *this);
766 0 : if (eErrCode != store_E_None)
767 0 : return eErrCode;
768 : }
769 :
770 : // Truncate internal data page.
771 0 : memset (&(xNode->m_pData[0]), 0, xNode->capacity());
772 0 : aPage.dataLength (0);
773 : }
774 :
775 : // Release page write access.
776 0 : eErrCode = base::releasePage (aDescr);
777 :
778 : // Release and free directory page.
779 0 : eErrCode = base::free (aPage.location());
780 : }
781 :
782 : // Remove entry.
783 0 : return remove_Impl (e);
784 : }
785 :
786 : /*
787 : * RebuildContext.
788 : */
789 0 : struct RebuildContext
790 : {
791 : /** Representation.
792 : */
793 : rtl::Reference<OStorePageBIOS> m_xBIOS;
794 : OStorePageBIOS::ScanContext m_aCtx;
795 : sal_uInt16 m_nPageSize;
796 :
797 : /** Construction.
798 : */
799 0 : RebuildContext (void)
800 0 : : m_xBIOS (new OStorePageBIOS()),
801 0 : m_nPageSize (0)
802 0 : {}
803 :
804 : /** initialize (PageBIOS and ScanContext).
805 : */
806 0 : storeError initialize (ILockBytes *pLockBytes, sal_uInt32 nMagic = 0)
807 : {
808 0 : storeError eErrCode = store_E_InvalidParameter;
809 0 : if (pLockBytes)
810 : {
811 0 : m_xBIOS->initialize (pLockBytes, store_AccessReadOnly, m_nPageSize);
812 0 : eErrCode = m_xBIOS->scanBegin (m_aCtx, nMagic);
813 : }
814 0 : return eErrCode;
815 : }
816 :
817 : /** initialize (ScanContext).
818 : */
819 0 : storeError initialize (sal_uInt32 nMagic = 0)
820 : {
821 0 : return m_xBIOS->scanBegin (m_aCtx, nMagic);
822 : }
823 :
824 : /** load (next ScanContext matching page).
825 : */
826 0 : storeError load (OStorePageObject &rPage)
827 : {
828 0 : if (m_aCtx.isValid())
829 0 : return m_xBIOS->scanNext (m_aCtx, rPage);
830 : else
831 0 : return store_E_CantSeek;
832 : }
833 : };
834 :
835 : /*
836 : * rebuild.
837 : * Precond: none.
838 : */
839 0 : storeError OStorePageManager::rebuild (
840 : ILockBytes *pSrcLB, ILockBytes *pDstLB)
841 : {
842 : // Acquire exclusive access.
843 0 : osl::MutexGuard aGuard(*this);
844 :
845 : // Check arguments.
846 0 : storeError eErrCode = store_E_InvalidParameter;
847 0 : if (!(pSrcLB && pDstLB))
848 0 : return eErrCode;
849 :
850 : // Initialize 'Source' rebuild context.
851 0 : RebuildContext aCtx;
852 0 : eErrCode = aCtx.initialize (pSrcLB, STORE_MAGIC_DIRECTORYPAGE);
853 0 : if (eErrCode != store_E_None)
854 0 : return eErrCode;
855 0 : rtl::Reference<OStorePageBIOS> xSrcBIOS (aCtx.m_xBIOS);
856 :
857 : // Initialize as 'Destination' with 'Source' page size.
858 0 : eErrCode = self::initialize (pDstLB, store_AccessCreate, aCtx.m_nPageSize);
859 0 : if (eErrCode != store_E_None)
860 0 : return eErrCode;
861 :
862 : // Pass One: Scan 'Source' directory pages.
863 : {
864 : // Scan 'Source' directory pages.
865 0 : OStoreDirectoryPageObject aSrcPage;
866 0 : while ((eErrCode = aCtx.load(aSrcPage)) == store_E_None)
867 : {
868 0 : OStoreDirectoryPageObject aDstPage;
869 0 : eErrCode = aDstPage.construct< inode >(base::allocator());
870 0 : if (eErrCode != store_E_None)
871 0 : break;
872 :
873 0 : inode_holder_type xSrcDir (aSrcPage.get());
874 0 : inode_holder_type xDstDir (aDstPage.get());
875 :
876 : // Copy NameBlock @@@ OLD @@@
877 0 : memcpy (&(xDstDir->m_aNameBlock), &(xSrcDir->m_aNameBlock), sizeof(xSrcDir->m_aNameBlock));
878 :
879 : // Obtain 'Source' data length.
880 0 : sal_uInt32 nDataLen = aSrcPage.dataLength();
881 0 : if (nDataLen > 0)
882 : {
883 : // Copy internal data area @@@ OLD @@@
884 0 : memcpy (&(xDstDir->m_pData[0]), &(xSrcDir->m_pData[0]), xSrcDir->capacity());
885 : }
886 :
887 : // Insert 'Destination' directory page.
888 0 : eErrCode = save_dirpage_Impl (aDstPage.key(), aDstPage);
889 0 : if (eErrCode != store_E_None)
890 0 : break;
891 :
892 : // Check for external data page scope.
893 0 : if (xSrcDir->scope(nDataLen) != inode::SCOPE_INTERNAL)
894 : {
895 : // Initialize 'Destination' data page.
896 : typedef OStoreDataPageData data;
897 0 : PageHolderObject< data > xData;
898 0 : if (!xData.construct(base::allocator()))
899 0 : return store_E_OutOfMemory;
900 :
901 : // Determine data page count.
902 : inode::ChunkDescriptor aDescr (
903 0 : nDataLen - xDstDir->capacity(), xData->capacity());
904 :
905 0 : sal_uInt32 i, n = aDescr.m_nPage;
906 0 : if (aDescr.m_nOffset) n += 1;
907 :
908 : // Copy data pages.
909 0 : OStoreDataPageObject aData;
910 0 : for (i = 0; i < n; i++)
911 : {
912 : // Read 'Source' data page.
913 0 : osl::MutexGuard aSrcGuard (*xSrcBIOS);
914 :
915 0 : eErrCode = aSrcPage.read (i, aData, *xSrcBIOS);
916 0 : if (eErrCode != store_E_None)
917 0 : continue;
918 :
919 : // Write 'Destination' data page. @@@ READONLY @@@
920 0 : eErrCode = aDstPage.write (i, aData, *this);
921 0 : }
922 : }
923 :
924 : // Update 'Destination' directory page.
925 0 : aDstPage.dataLength (nDataLen);
926 0 : eErrCode = base::saveObjectAt (aDstPage, aDstPage.location());
927 0 : }
928 :
929 : // Save directory scan results.
930 0 : flush();
931 : }
932 :
933 : // Pass Two: Scan 'Source' BTree nodes.
934 : {
935 : // Re-start 'Source' rebuild context.
936 0 : aCtx.initialize (STORE_MAGIC_BTREENODE);
937 :
938 : // Scan 'Source' BTree nodes.
939 0 : OStoreBTreeNodeObject aNode;
940 0 : while ((eErrCode = aCtx.load(aNode)) == store_E_None)
941 : {
942 : // Check for leaf node.
943 0 : PageHolderObject< page > xNode (aNode.get());
944 0 : if (xNode->depth() == 0)
945 : {
946 0 : sal_uInt16 i, n = xNode->usageCount();
947 0 : for (i = 0; i < n; i++)
948 : {
949 0 : entry e (xNode->m_pData[i]);
950 :
951 : // Check for Hard link.
952 0 : if (e.m_nAttrib & STORE_ATTRIB_ISLINK)
953 : {
954 : // Load the hard link destination.
955 0 : OStoreDirectoryPageObject aSrcPage;
956 0 : eErrCode = xSrcBIOS->loadObjectAt (aSrcPage, e.m_aLink.location());
957 0 : if (eErrCode == store_E_None)
958 : {
959 0 : OStorePageKey aDstKey (aSrcPage.key());
960 0 : eErrCode = link (e.m_aKey, aDstKey);
961 : }
962 0 : e.m_nAttrib &= ~STORE_ATTRIB_ISLINK;
963 : }
964 :
965 0 : if (e.m_nAttrib)
966 : {
967 : // Ordinary attributes.
968 0 : sal_uInt32 nAttrib = 0;
969 0 : eErrCode = attrib (e.m_aKey, 0, e.m_nAttrib, nAttrib);
970 : }
971 : }
972 : }
973 0 : }
974 :
975 : // Save BTree node scan results.
976 0 : flush();
977 : }
978 :
979 : // Done.
980 0 : return store_E_None;
981 : }
982 :
983 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|