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