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