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