File: | store/source/storpage.cxx |
Location: | line 132, column 5 |
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: */ |