build fix
[LibreOffice.git] / store / source / storpage.cxx
blob3d10ec04e4fc00247869d52f008460189a111fd5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "storpage.hxx"
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"
29 #include "store/types.h"
31 #include "object.hxx"
32 #include "lockbyte.hxx"
34 #include "storbase.hxx"
35 #include "stordata.hxx"
36 #include "stortree.hxx"
38 using namespace store;
40 /*========================================================================
42 * OStorePageManager implementation.
44 *======================================================================*/
45 const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
48 * OStorePageManager.
50 OStorePageManager::OStorePageManager()
55 * ~OStorePageManager.
57 OStorePageManager::~OStorePageManager()
62 * isKindOf.
64 bool OStorePageManager::isKindOf (sal_uInt32 nTypeId)
66 return (nTypeId == m_nTypeId);
70 * initialize (two-phase construction).
71 * Precond: none.
73 storeError OStorePageManager::initialize (
74 ILockBytes * pLockBytes,
75 storeAccessMode eAccessMode,
76 sal_uInt16 & rnPageSize)
78 // Acquire exclusive access.
79 osl::MutexGuard aGuard(*this);
81 // Check arguments.
82 if (!pLockBytes)
83 return store_E_InvalidParameter;
85 // Initialize base.
86 storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
87 if (eErrCode != store_E_None)
88 return eErrCode;
90 // Check for (not) writeable.
91 if (!base::isWriteable())
93 // Readonly. Load RootNode.
94 return base::loadObjectAt (m_aRoot, rnPageSize);
97 // Writeable. Load or Create RootNode.
98 eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
99 if (eErrCode == store_E_Pending)
101 // Creation notification.
102 PageHolderObject< page > xRoot (m_aRoot.get());
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));
108 // Save RootNode.
109 eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
112 // Done.
113 return eErrCode;
117 * find_lookup (w/o split()).
118 * Internal: Precond: initialized, readable, exclusive access.
120 storeError OStorePageManager::find_lookup (
121 OStoreBTreeNodeObject & rNode,
122 sal_uInt16 & rIndex,
123 OStorePageKey const & rKey)
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;
130 // Greater or Equal.
131 PageHolderObject< page > xPage (rNode.get());
132 SAL_WARN_IF(rIndex >= xPage->usageCount(), "store", "store::PageManager::find_lookup(): logic error");
133 entry e (xPage->m_pData[rIndex]);
135 // Check for exact match.
136 if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
138 // Page not present.
139 return store_E_NotExists;
142 // Check address.
143 if (e.m_aLink.location() == STORE_PAGE_NULL)
145 // Page not present.
146 return store_E_NotExists;
149 return store_E_None;
153 * remove_Impl (possibly down from root).
154 * Internal: Precond: initialized, writeable, exclusive access.
157 storeError OStorePageManager::remove_Impl (entry & rEntry)
159 OStoreBTreeNodeObject aNode (m_aRoot.get());
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))
166 // Path to entry not exists (Must not happen(?)).
167 return store_E_NotExists;
170 // Compare entry.
171 entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
173 // Iterate down until equal match.
174 while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
176 // Check link address.
177 sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
178 if (nAddr == STORE_PAGE_NULL)
180 // Path to entry not exists (Must not happen(?)).
181 return store_E_NotExists;
184 // Load link page.
185 storeError eErrCode = loadObjectAt (aNode, nAddr);
186 if (eErrCode != store_E_None)
187 return eErrCode;
189 PageHolderObject< page > xNext (aNode.get());
190 xNext.swap (xPage);
192 // Check index.
193 i = xPage->find (rEntry);
194 n = xPage->usageCount();
195 if (!(i < n))
197 // Path to entry not exists (Must not happen(?)).
198 return store_E_NotExists;
201 // Compare entry.
202 result = rEntry.compare (xPage->m_pData[i]);
205 SAL_WARN_IF(
206 result == entry::COMPARE_LESS,
207 "store",
208 "OStorePageManager::remove(): find failed");
210 // Check entry comparison.
211 if (result == entry::COMPARE_LESS)
213 // Must not happen.
214 return store_E_Unknown;
217 // Remove down from current page (recursive).
218 return aNode.remove (i, rEntry, *this);
222 * namei.
223 * Precond: none (static).
225 storeError OStorePageManager::namei (
226 const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
228 // Check parameter.
229 if (!(pPath && pName))
230 return store_E_InvalidParameter;
232 // Check name length.
233 if (!(pName->length < STORE_MAXIMUM_NAMESIZE))
234 return store_E_NameTooLong;
236 // Transform pathname into key.
237 rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
238 rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
240 // Done.
241 return store_E_None;
245 * iget.
246 * Precond: initialized.
248 storeError OStorePageManager::iget (
249 OStoreDirectoryPageObject & rPage,
250 sal_uInt32 nAttrib,
251 const rtl_String * pPath,
252 const rtl_String * pName,
253 storeAccessMode eMode)
255 // Acquire exclusive access.
256 osl::MutexGuard aGuard(*this);
258 // Check precond.
259 if (!self::isValid())
260 return store_E_InvalidAccess;
262 // Setup inode page key.
263 OStorePageKey aKey;
264 storeError eErrCode = namei (pPath, pName, aKey);
265 if (eErrCode != store_E_None)
266 return eErrCode;
268 // Check for directory.
269 if (nAttrib & STORE_ATTRIB_ISDIR)
271 // Ugly, but necessary (backward compatibility).
272 aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
275 // Load inode page.
276 eErrCode = load_dirpage_Impl (aKey, rPage);
277 if (eErrCode != store_E_None)
279 // Check mode and reason.
280 if (eErrCode != store_E_NotExists)
281 return eErrCode;
283 if (eMode == storeAccessMode::ReadWrite)
284 return store_E_NotExists;
285 if (eMode == storeAccessMode::ReadOnly)
286 return store_E_NotExists;
288 if (!base::isWriteable())
289 return store_E_AccessViolation;
291 // Create inode page.
292 eErrCode = rPage.construct< inode >(base::allocator());
293 if (eErrCode != store_E_None)
294 return eErrCode;
296 // Setup inode nameblock.
297 PageHolderObject< inode > xPage (rPage.get());
299 rPage.key (aKey);
300 rPage.attrib (nAttrib);
302 memcpy (
303 &(xPage->m_aNameBlock.m_pData[0]),
304 pName->buffer, pName->length);
306 // Save inode page.
307 eErrCode = save_dirpage_Impl (aKey, rPage);
308 if (eErrCode != store_E_None)
309 return eErrCode;
312 // Check for symbolic link.
313 if (rPage.attrib() & STORE_ATTRIB_ISLINK)
315 // Obtain 'Destination' page key.
316 PageHolderObject< inode > xPage (rPage.get());
317 OStorePageKey aDstKey;
318 memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
320 // Load 'Destination' inode.
321 eErrCode = load_dirpage_Impl (aDstKey, rPage);
322 if (eErrCode != store_E_None)
323 return eErrCode;
326 // Done.
327 return store_E_None;
331 * iterate.
332 * Precond: initialized.
333 * ToDo: skip hardlink entries.
335 storeError OStorePageManager::iterate (
336 OStorePageKey & rKey,
337 OStorePageLink & rLink,
338 sal_uInt32 & rAttrib)
340 // Acquire exclusive access.
341 osl::MutexGuard aGuard(*this);
343 // Check precond.
344 if (!self::isValid())
345 return store_E_InvalidAccess;
347 // Find NodePage and Index.
348 OStoreBTreeNodeObject aNode;
349 sal_uInt16 i = 0;
350 storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
351 if (eErrCode != store_E_None)
352 return eErrCode;
354 // GreaterEqual. Found next entry.
355 PageHolderObject< page > xNode (aNode.get());
356 entry e (xNode->m_pData[i]);
358 // Setup result.
359 rKey = e.m_aKey;
360 rLink = e.m_aLink;
361 rAttrib = store::ntohl(e.m_nAttrib);
363 // Done.
364 return store_E_None;
368 * load => private: iget() @@@
369 * Internal: Precond: initialized, exclusive access.
371 storeError OStorePageManager::load_dirpage_Impl (
372 const OStorePageKey &rKey,
373 OStoreDirectoryPageObject &rPage)
375 // Find Node and Index.
376 OStoreBTreeNodeObject aNode;
377 sal_uInt16 i = 0;
378 storeError eErrCode = find_lookup (aNode, i, rKey);
379 if (eErrCode != store_E_None)
380 return eErrCode;
382 // Existing entry. Load page.
383 PageHolderObject< page > xNode (aNode.get());
384 entry e (xNode->m_pData[i]);
385 return loadObjectAt (rPage, e.m_aLink.location());
389 * save => private: iget(), rebuild() @@@
390 * Internal: Precond: initialized, writeable, exclusive access.
392 storeError OStorePageManager::save_dirpage_Impl (
393 const OStorePageKey &rKey,
394 OStoreDirectoryPageObject &rPage)
396 // Find NodePage and Index.
397 node aNode;
398 sal_uInt16 i = 0;
400 storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
401 PageHolderObject< page > xNode (aNode.get());
402 if (eErrCode != store_E_None)
404 if (eErrCode != store_E_AlreadyExists)
405 return eErrCode;
407 // Existing entry.
408 entry e (xNode->m_pData[i]);
409 if (e.m_aLink.location() != STORE_PAGE_NULL)
411 // Save page to existing location.
412 return saveObjectAt (rPage, e.m_aLink.location());
415 // Allocate page.
416 eErrCode = base::allocate (rPage);
417 if (eErrCode != store_E_None)
418 return eErrCode;
420 // Update page location.
421 xNode->m_pData[i].m_aLink = rPage.location();
423 // Save modified NodePage.
424 return saveObjectAt (aNode, aNode.location());
427 // Allocate page.
428 eErrCode = base::allocate (rPage);
429 if (eErrCode != store_E_None)
430 return eErrCode;
432 // Insert.
433 OStorePageLink aLink (rPage.location());
434 xNode->insert (i + 1, entry (rKey, aLink));
436 // Save modified NodePage.
437 return saveObjectAt (aNode, aNode.location());
441 * remove.
442 * Precond: initialized, writeable.
444 storeError OStorePageManager::remove (const OStorePageKey &rKey)
446 // Acquire exclusive access.
447 osl::MutexGuard aGuard(*this);
449 // Check precond.
450 if (!self::isValid())
451 return store_E_InvalidAccess;
453 if (!base::isWriteable())
454 return store_E_AccessViolation;
456 // Find NodePage and index.
457 OStoreBTreeNodeObject aNodePage;
458 sal_uInt16 i = 0;
459 storeError eErrCode = find_lookup (aNodePage, i, rKey);
460 if (eErrCode != store_E_None)
461 return eErrCode;
463 // Existing entry.
464 PageHolderObject< page > xNodePage (aNodePage.get());
465 entry e (xNodePage->m_pData[i]);
467 // Check for (not a) hardlink.
468 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
470 // Load directory page.
471 OStoreDirectoryPageObject aPage;
472 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
473 if (eErrCode != store_E_None)
474 return eErrCode;
476 inode_holder_type xNode (aPage.get());
478 // Acquire page write access.
479 OStorePageDescriptor aDescr (xNode->m_aDescr);
480 eErrCode = base::acquirePage (aDescr, storeAccessMode::ReadWrite);
481 if (eErrCode != store_E_None)
482 return eErrCode;
484 // Check for symbolic link.
485 if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
487 // Ordinary inode. Determine 'Data' scope.
488 inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
489 if (eScope == inode::SCOPE_EXTERNAL)
491 // External 'Data' scope. Truncate all external data pages.
492 eErrCode = aPage.truncate (0, *this);
493 if (eErrCode != store_E_None)
494 return eErrCode;
497 // Truncate internal data page.
498 memset (&(xNode->m_pData[0]), 0, xNode->capacity());
499 aPage.dataLength (0);
502 // Release page write access.
503 base::releasePage (aDescr);
505 // Release and free directory page.
506 (void)base::free (aPage.location());
509 // Remove entry.
510 return remove_Impl (e);
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */