vcl: sfx2: LOK: Support per-view popup windows
[LibreOffice.git] / store / source / storpage.cxx
blob4eb9c25964429ad241c84c3706c741b02891fdd9
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 <osl/mutex.hxx>
27 #include <store/types.h>
29 #include "storbase.hxx"
30 #include "stordata.hxx"
31 #include "stortree.hxx"
33 using namespace store;
35 /*========================================================================
37 * OStorePageManager implementation.
39 *======================================================================*/
40 const sal_uInt32 OStorePageManager::m_nTypeId = sal_uInt32(0x62190120);
43 * OStorePageManager.
45 OStorePageManager::OStorePageManager()
50 * ~OStorePageManager.
52 OStorePageManager::~OStorePageManager()
57 * isKindOf.
59 bool OStorePageManager::isKindOf (sal_uInt32 nTypeId)
61 return (nTypeId == m_nTypeId);
65 * initialize (two-phase construction).
66 * Precond: none.
68 storeError OStorePageManager::initialize (
69 ILockBytes * pLockBytes,
70 storeAccessMode eAccessMode,
71 sal_uInt16 & rnPageSize)
73 // Acquire exclusive access.
74 osl::MutexGuard aGuard(*this);
76 // Check arguments.
77 if (!pLockBytes)
78 return store_E_InvalidParameter;
80 // Initialize base.
81 storeError eErrCode = base::initialize (pLockBytes, eAccessMode, rnPageSize);
82 if (eErrCode != store_E_None)
83 return eErrCode;
85 // Check for (not) writeable.
86 if (!base::isWriteable())
88 // Readonly. Load RootNode.
89 return base::loadObjectAt (m_aRoot, rnPageSize);
92 // Writeable. Load or Create RootNode.
93 eErrCode = m_aRoot.loadOrCreate (rnPageSize, *this);
94 if (eErrCode == store_E_Pending)
96 // Creation notification.
97 PageHolderObject< page > xRoot (m_aRoot.get());
99 // Pre-allocate left most entry (ugly, but we can't insert to left).
100 OStorePageKey aKey (rtl_crc32 (0, "/", 1), 0);
101 xRoot->insert (0, entry(aKey));
103 // Save RootNode.
104 eErrCode = base::saveObjectAt (m_aRoot, rnPageSize);
107 // Done.
108 return eErrCode;
112 * find_lookup (w/o split()).
113 * Internal: Precond: initialized, readable, exclusive access.
115 storeError OStorePageManager::find_lookup (
116 OStoreBTreeNodeObject & rNode,
117 sal_uInt16 & rIndex,
118 OStorePageKey const & rKey)
120 // Find Node and Index.
121 storeError eErrCode = m_aRoot.find_lookup (rNode, rIndex, rKey, *this);
122 if (eErrCode != store_E_None)
123 return eErrCode;
125 // Greater or Equal.
126 PageHolderObject< page > xPage (rNode.get());
127 SAL_WARN_IF(rIndex >= xPage->usageCount(), "store", "store::PageManager::find_lookup(): logic error");
128 entry e (xPage->m_pData[rIndex]);
130 // Check for exact match.
131 if (e.compare(entry(rKey)) != entry::COMPARE_EQUAL)
133 // Page not present.
134 return store_E_NotExists;
137 // Check address.
138 if (e.m_aLink.location() == STORE_PAGE_NULL)
140 // Page not present.
141 return store_E_NotExists;
144 return store_E_None;
148 * remove_Impl (possibly down from root).
149 * Internal: Precond: initialized, writeable, exclusive access.
152 storeError OStorePageManager::remove_Impl (entry & rEntry)
154 OStoreBTreeNodeObject aNode (m_aRoot.get());
156 // Check current page index.
157 PageHolderObject< page > xPage (aNode.get());
158 sal_uInt16 i = xPage->find (rEntry), n = xPage->usageCount();
159 if (i >= n)
161 // Path to entry not exists (Must not happen(?)).
162 return store_E_NotExists;
165 // Compare entry.
166 entry::CompareResult result = rEntry.compare (xPage->m_pData[i]);
168 // Iterate down until equal match.
169 while ((result == entry::COMPARE_GREATER) && (xPage->depth() > 0))
171 // Check link address.
172 sal_uInt32 const nAddr = xPage->m_pData[i].m_aLink.location();
173 if (nAddr == STORE_PAGE_NULL)
175 // Path to entry not exists (Must not happen(?)).
176 return store_E_NotExists;
179 // Load link page.
180 storeError eErrCode = loadObjectAt (aNode, nAddr);
181 if (eErrCode != store_E_None)
182 return eErrCode;
184 PageHolderObject< page > xNext (aNode.get());
185 xNext.swap (xPage);
187 // Check index.
188 i = xPage->find (rEntry);
189 n = xPage->usageCount();
190 if (i >= n)
192 // Path to entry not exists (Must not happen(?)).
193 return store_E_NotExists;
196 // Compare entry.
197 result = rEntry.compare (xPage->m_pData[i]);
200 SAL_WARN_IF(
201 result == entry::COMPARE_LESS,
202 "store",
203 "OStorePageManager::remove(): find failed");
205 // Check entry comparison.
206 if (result == entry::COMPARE_LESS)
208 // Must not happen.
209 return store_E_Unknown;
212 // Remove down from current page (recursive).
213 return aNode.remove (i, rEntry, *this);
217 * namei.
218 * Precond: none (static).
220 storeError OStorePageManager::namei (
221 const rtl_String *pPath, const rtl_String *pName, OStorePageKey &rKey)
223 // Check parameter.
224 if (!(pPath && pName))
225 return store_E_InvalidParameter;
227 // Check name length.
228 if (pName->length >= STORE_MAXIMUM_NAMESIZE)
229 return store_E_NameTooLong;
231 // Transform pathname into key.
232 rKey.m_nLow = store::htonl(rtl_crc32 (0, pName->buffer, pName->length));
233 rKey.m_nHigh = store::htonl(rtl_crc32 (0, pPath->buffer, pPath->length));
235 // Done.
236 return store_E_None;
240 * iget.
241 * Precond: initialized.
243 storeError OStorePageManager::iget (
244 OStoreDirectoryPageObject & rPage,
245 sal_uInt32 nAttrib,
246 const rtl_String * pPath,
247 const rtl_String * pName,
248 storeAccessMode eMode)
250 // Acquire exclusive access.
251 osl::MutexGuard aGuard(*this);
253 // Check precond.
254 if (!self::isValid())
255 return store_E_InvalidAccess;
257 // Setup inode page key.
258 OStorePageKey aKey;
259 storeError eErrCode = namei (pPath, pName, aKey);
260 if (eErrCode != store_E_None)
261 return eErrCode;
263 // Check for directory.
264 if (nAttrib & STORE_ATTRIB_ISDIR)
266 // Ugly, but necessary (backward compatibility).
267 aKey.m_nLow = store::htonl(rtl_crc32 (store::ntohl(aKey.m_nLow), "/", 1));
270 // Load inode page.
271 eErrCode = load_dirpage_Impl (aKey, rPage);
272 if (eErrCode != store_E_None)
274 // Check mode and reason.
275 if (eErrCode != store_E_NotExists)
276 return eErrCode;
278 if (eMode == storeAccessMode::ReadWrite)
279 return store_E_NotExists;
280 if (eMode == storeAccessMode::ReadOnly)
281 return store_E_NotExists;
283 if (!base::isWriteable())
284 return store_E_AccessViolation;
286 // Create inode page.
287 eErrCode = rPage.construct< inode >(base::allocator());
288 if (eErrCode != store_E_None)
289 return eErrCode;
291 // Setup inode nameblock.
292 PageHolderObject< inode > xPage (rPage.get());
294 rPage.key (aKey);
295 rPage.attrib (nAttrib);
297 memcpy (
298 &(xPage->m_aNameBlock.m_pData[0]),
299 pName->buffer, pName->length);
301 // Save inode page.
302 eErrCode = save_dirpage_Impl (aKey, rPage);
303 if (eErrCode != store_E_None)
304 return eErrCode;
307 // Check for symbolic link.
308 if (rPage.attrib() & STORE_ATTRIB_ISLINK)
310 // Obtain 'Destination' page key.
311 PageHolderObject< inode > xPage (rPage.get());
312 OStorePageKey aDstKey;
313 memcpy (&aDstKey, &(xPage->m_pData[0]), sizeof(aDstKey));
315 // Load 'Destination' inode.
316 eErrCode = load_dirpage_Impl (aDstKey, rPage);
317 if (eErrCode != store_E_None)
318 return eErrCode;
321 // Done.
322 return store_E_None;
326 * iterate.
327 * Precond: initialized.
328 * ToDo: skip hardlink entries.
330 storeError OStorePageManager::iterate (
331 OStorePageKey & rKey,
332 OStorePageLink & rLink,
333 sal_uInt32 & rAttrib)
335 // Acquire exclusive access.
336 osl::MutexGuard aGuard(*this);
338 // Check precond.
339 if (!self::isValid())
340 return store_E_InvalidAccess;
342 // Find NodePage and Index.
343 OStoreBTreeNodeObject aNode;
344 sal_uInt16 i = 0;
345 storeError eErrCode = m_aRoot.find_lookup (aNode, i, rKey, *this);
346 if (eErrCode != store_E_None)
347 return eErrCode;
349 // GreaterEqual. Found next entry.
350 PageHolderObject< page > xNode (aNode.get());
351 entry e (xNode->m_pData[i]);
353 // Setup result.
354 rKey = e.m_aKey;
355 rLink = e.m_aLink;
356 rAttrib = store::ntohl(e.m_nAttrib);
358 // Done.
359 return store_E_None;
363 * load => private: iget() @@@
364 * Internal: Precond: initialized, exclusive access.
366 storeError OStorePageManager::load_dirpage_Impl (
367 const OStorePageKey &rKey,
368 OStoreDirectoryPageObject &rPage)
370 // Find Node and Index.
371 OStoreBTreeNodeObject aNode;
372 sal_uInt16 i = 0;
373 storeError eErrCode = find_lookup (aNode, i, rKey);
374 if (eErrCode != store_E_None)
375 return eErrCode;
377 // Existing entry. Load page.
378 PageHolderObject< page > xNode (aNode.get());
379 entry e (xNode->m_pData[i]);
380 return loadObjectAt (rPage, e.m_aLink.location());
384 * save => private: iget(), rebuild() @@@
385 * Internal: Precond: initialized, writeable, exclusive access.
387 storeError OStorePageManager::save_dirpage_Impl (
388 const OStorePageKey &rKey,
389 OStoreDirectoryPageObject &rPage)
391 // Find NodePage and Index.
392 node aNode;
393 sal_uInt16 i = 0;
395 storeError eErrCode = m_aRoot.find_insert (aNode, i, rKey, *this);
396 PageHolderObject< page > xNode (aNode.get());
397 if (eErrCode != store_E_None)
399 if (eErrCode != store_E_AlreadyExists)
400 return eErrCode;
402 // Existing entry.
403 entry e (xNode->m_pData[i]);
404 if (e.m_aLink.location() != STORE_PAGE_NULL)
406 // Save page to existing location.
407 return saveObjectAt (rPage, e.m_aLink.location());
410 // Allocate page.
411 eErrCode = base::allocate (rPage);
412 if (eErrCode != store_E_None)
413 return eErrCode;
415 // Update page location.
416 xNode->m_pData[i].m_aLink = rPage.location();
418 // Save modified NodePage.
419 return saveObjectAt (aNode, aNode.location());
422 // Allocate page.
423 eErrCode = base::allocate (rPage);
424 if (eErrCode != store_E_None)
425 return eErrCode;
427 // Insert.
428 OStorePageLink aLink (rPage.location());
429 xNode->insert (i + 1, entry (rKey, aLink));
431 // Save modified NodePage.
432 return saveObjectAt (aNode, aNode.location());
436 * remove.
437 * Precond: initialized, writeable.
439 storeError OStorePageManager::remove (const OStorePageKey &rKey)
441 // Acquire exclusive access.
442 osl::MutexGuard aGuard(*this);
444 // Check precond.
445 if (!self::isValid())
446 return store_E_InvalidAccess;
448 if (!base::isWriteable())
449 return store_E_AccessViolation;
451 // Find NodePage and index.
452 OStoreBTreeNodeObject aNodePage;
453 sal_uInt16 i = 0;
454 storeError eErrCode = find_lookup (aNodePage, i, rKey);
455 if (eErrCode != store_E_None)
456 return eErrCode;
458 // Existing entry.
459 PageHolderObject< page > xNodePage (aNodePage.get());
460 entry e (xNodePage->m_pData[i]);
462 // Check for (not a) hardlink.
463 if (!(store::ntohl(e.m_nAttrib) & STORE_ATTRIB_ISLINK))
465 // Load directory page.
466 OStoreDirectoryPageObject aPage;
467 eErrCode = base::loadObjectAt (aPage, e.m_aLink.location());
468 if (eErrCode != store_E_None)
469 return eErrCode;
471 inode_holder_type xNode (aPage.get());
473 // Acquire page write access.
474 OStorePageDescriptor aDescr (xNode->m_aDescr);
475 eErrCode = base::acquirePage (aDescr, storeAccessMode::ReadWrite);
476 if (eErrCode != store_E_None)
477 return eErrCode;
479 // Check for symbolic link.
480 if (!(aPage.attrib() & STORE_ATTRIB_ISLINK))
482 // Ordinary inode. Determine 'Data' scope.
483 inode::ChunkScope eScope = xNode->scope (aPage.dataLength());
484 if (eScope == inode::SCOPE_EXTERNAL)
486 // External 'Data' scope. Truncate all external data pages.
487 eErrCode = aPage.truncate (0, *this);
488 if (eErrCode != store_E_None)
489 return eErrCode;
492 // Truncate internal data page.
493 memset (&(xNode->m_pData[0]), 0, xNode->capacity());
494 aPage.dataLength (0);
497 // Release page write access.
498 base::releasePage (aDescr);
500 // Release and free directory page.
501 (void)base::free (aPage.location());
504 // Remove entry.
505 return remove_Impl (e);
509 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */