1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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);
45 OStorePageManager::OStorePageManager()
52 OStorePageManager::~OStorePageManager()
59 bool OStorePageManager::isKindOf (sal_uInt32 nTypeId
)
61 return (nTypeId
== m_nTypeId
);
65 * initialize (two-phase construction).
68 storeError
OStorePageManager::initialize (
69 ILockBytes
* pLockBytes
,
70 storeAccessMode eAccessMode
,
71 sal_uInt16
& rnPageSize
)
73 // Acquire exclusive access.
74 osl::MutexGuard
aGuard(*this);
78 return store_E_InvalidParameter
;
81 storeError eErrCode
= base::initialize (pLockBytes
, eAccessMode
, rnPageSize
);
82 if (eErrCode
!= store_E_None
)
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
));
104 eErrCode
= base::saveObjectAt (m_aRoot
, rnPageSize
);
112 * find_lookup (w/o split()).
113 * Internal: Precond: initialized, readable, exclusive access.
115 storeError
OStorePageManager::find_lookup (
116 OStoreBTreeNodeObject
& rNode
,
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
)
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
)
134 return store_E_NotExists
;
138 if (e
.m_aLink
.location() == STORE_PAGE_NULL
)
141 return store_E_NotExists
;
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();
161 // Path to entry not exists (Must not happen(?)).
162 return store_E_NotExists
;
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
;
180 storeError eErrCode
= loadObjectAt (aNode
, nAddr
);
181 if (eErrCode
!= store_E_None
)
184 PageHolderObject
< page
> xNext (aNode
.get());
188 i
= xPage
->find (rEntry
);
189 n
= xPage
->usageCount();
192 // Path to entry not exists (Must not happen(?)).
193 return store_E_NotExists
;
197 result
= rEntry
.compare (xPage
->m_pData
[i
]);
201 result
== entry::COMPARE_LESS
,
203 "OStorePageManager::remove(): find failed");
205 // Check entry comparison.
206 if (result
== entry::COMPARE_LESS
)
209 return store_E_Unknown
;
212 // Remove down from current page (recursive).
213 return aNode
.remove (i
, rEntry
, *this);
218 * Precond: none (static).
220 storeError
OStorePageManager::namei (
221 const rtl_String
*pPath
, const rtl_String
*pName
, OStorePageKey
&rKey
)
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
));
241 * Precond: initialized.
243 storeError
OStorePageManager::iget (
244 OStoreDirectoryPageObject
& rPage
,
246 const rtl_String
* pPath
,
247 const rtl_String
* pName
,
248 storeAccessMode eMode
)
250 // Acquire exclusive access.
251 osl::MutexGuard
aGuard(*this);
254 if (!self::isValid())
255 return store_E_InvalidAccess
;
257 // Setup inode page key.
259 storeError eErrCode
= namei (pPath
, pName
, aKey
);
260 if (eErrCode
!= store_E_None
)
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));
271 eErrCode
= load_dirpage_Impl (aKey
, rPage
);
272 if (eErrCode
!= store_E_None
)
274 // Check mode and reason.
275 if (eErrCode
!= store_E_NotExists
)
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
)
291 // Setup inode nameblock.
292 PageHolderObject
< inode
> xPage (rPage
.get());
295 rPage
.attrib (nAttrib
);
298 &(xPage
->m_aNameBlock
.m_pData
[0]),
299 pName
->buffer
, pName
->length
);
302 eErrCode
= save_dirpage_Impl (aKey
, rPage
);
303 if (eErrCode
!= store_E_None
)
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
)
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);
339 if (!self::isValid())
340 return store_E_InvalidAccess
;
342 // Find NodePage and Index.
343 OStoreBTreeNodeObject aNode
;
345 storeError eErrCode
= m_aRoot
.find_lookup (aNode
, i
, rKey
, *this);
346 if (eErrCode
!= store_E_None
)
349 // GreaterEqual. Found next entry.
350 PageHolderObject
< page
> xNode (aNode
.get());
351 entry
e (xNode
->m_pData
[i
]);
356 rAttrib
= store::ntohl(e
.m_nAttrib
);
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
;
373 storeError eErrCode
= find_lookup (aNode
, i
, rKey
);
374 if (eErrCode
!= store_E_None
)
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.
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
)
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());
411 eErrCode
= base::allocate (rPage
);
412 if (eErrCode
!= store_E_None
)
415 // Update page location.
416 xNode
->m_pData
[i
].m_aLink
= rPage
.location();
418 // Save modified NodePage.
419 return saveObjectAt (aNode
, aNode
.location());
423 eErrCode
= base::allocate (rPage
);
424 if (eErrCode
!= store_E_None
)
428 OStorePageLink
aLink (rPage
.location());
429 xNode
->insert (i
+ 1, entry (rKey
, aLink
));
431 // Save modified NodePage.
432 return saveObjectAt (aNode
, aNode
.location());
437 * Precond: initialized, writeable.
439 storeError
OStorePageManager::remove (const OStorePageKey
&rKey
)
441 // Acquire exclusive access.
442 osl::MutexGuard
aGuard(*this);
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
;
454 storeError eErrCode
= find_lookup (aNodePage
, i
, rKey
);
455 if (eErrCode
!= store_E_None
)
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
)
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
)
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
)
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());
505 return remove_Impl (e
);
509 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */