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 const sal_uInt32
OStorePageManager::m_nTypeId
= sal_uInt32(0x62190120);
37 OStorePageManager::OStorePageManager()
41 OStorePageManager::~OStorePageManager()
45 bool OStorePageManager::isKindOf (sal_uInt32 nTypeId
)
47 return (nTypeId
== m_nTypeId
);
51 * initialize (two-phase construction).
54 storeError
OStorePageManager::initialize (
55 ILockBytes
* pLockBytes
,
56 storeAccessMode eAccessMode
,
57 sal_uInt16
& rnPageSize
)
59 // Acquire exclusive access.
60 osl::MutexGuard
aGuard(*this);
64 return store_E_InvalidParameter
;
67 storeError eErrCode
= base::initialize (pLockBytes
, eAccessMode
, rnPageSize
);
68 if (eErrCode
!= store_E_None
)
71 // Check for (not) writeable.
72 if (!base::isWriteable())
74 // Readonly. Load RootNode.
75 return base::loadObjectAt (m_aRoot
, rnPageSize
);
78 // Writeable. Load or Create RootNode.
79 eErrCode
= m_aRoot
.loadOrCreate (rnPageSize
, *this);
80 if (eErrCode
== store_E_Pending
)
82 // Creation notification.
83 PageHolderObject
< page
> xRoot (m_aRoot
.get());
85 // Pre-allocate left most entry (ugly, but we can't insert to left).
86 OStorePageKey
aKey (rtl_crc32 (0, "/", 1), 0);
87 xRoot
->insert (0, entry(aKey
));
90 eErrCode
= base::saveObjectAt (m_aRoot
, rnPageSize
);
98 * find_lookup (w/o split()).
99 * Internal: Precond: initialized, readable, exclusive access.
101 storeError
OStorePageManager::find_lookup (
102 OStoreBTreeNodeObject
& rNode
,
104 OStorePageKey
const & rKey
)
106 // Find Node and Index.
107 storeError eErrCode
= m_aRoot
.find_lookup (rNode
, rIndex
, rKey
, *this);
108 if (eErrCode
!= store_E_None
)
112 PageHolderObject
< page
> xPage (rNode
.get());
113 SAL_WARN_IF(rIndex
>= xPage
->usageCount(), "store", "store::PageManager::find_lookup(): logic error");
114 entry
e (xPage
->m_pData
[rIndex
]);
116 // Check for exact match.
117 if (e
.compare(entry(rKey
)) != entry::COMPARE_EQUAL
)
120 return store_E_NotExists
;
124 if (e
.m_aLink
.location() == STORE_PAGE_NULL
)
127 return store_E_NotExists
;
134 * remove_Impl (possibly down from root).
135 * Internal: Precond: initialized, writeable, exclusive access.
138 storeError
OStorePageManager::remove_Impl (entry
& rEntry
)
140 OStoreBTreeNodeObject
aNode (m_aRoot
.get());
142 // Check current page index.
143 PageHolderObject
< page
> xPage (aNode
.get());
144 sal_uInt16 i
= xPage
->find (rEntry
), n
= xPage
->usageCount();
147 // Path to entry not exists (Must not happen(?)).
148 return store_E_NotExists
;
152 entry::CompareResult result
= rEntry
.compare (xPage
->m_pData
[i
]);
154 // Iterate down until equal match.
155 while ((result
== entry::COMPARE_GREATER
) && (xPage
->depth() > 0))
157 // Check link address.
158 sal_uInt32
const nAddr
= xPage
->m_pData
[i
].m_aLink
.location();
159 if (nAddr
== STORE_PAGE_NULL
)
161 // Path to entry not exists (Must not happen(?)).
162 return store_E_NotExists
;
166 storeError eErrCode
= loadObjectAt (aNode
, nAddr
);
167 if (eErrCode
!= store_E_None
)
170 PageHolderObject
< page
> xNext (aNode
.get());
174 i
= xPage
->find (rEntry
);
175 n
= xPage
->usageCount();
178 // Path to entry not exists (Must not happen(?)).
179 return store_E_NotExists
;
183 result
= rEntry
.compare (xPage
->m_pData
[i
]);
187 result
== entry::COMPARE_LESS
,
189 "OStorePageManager::remove(): find failed");
191 // Check entry comparison.
192 if (result
== entry::COMPARE_LESS
)
195 return store_E_Unknown
;
198 // Remove down from current page (recursive).
199 return aNode
.remove (i
, rEntry
, *this);
204 * Precond: none (static).
206 storeError
OStorePageManager::namei (
207 const rtl_String
*pPath
, const rtl_String
*pName
, OStorePageKey
&rKey
)
210 if (!(pPath
&& pName
))
211 return store_E_InvalidParameter
;
213 // Check name length.
214 if (pName
->length
>= STORE_MAXIMUM_NAMESIZE
)
215 return store_E_NameTooLong
;
217 // Transform pathname into key.
218 rKey
.m_nLow
= store::htonl(rtl_crc32 (0, pName
->buffer
, pName
->length
));
219 rKey
.m_nHigh
= store::htonl(rtl_crc32 (0, pPath
->buffer
, pPath
->length
));
227 * Precond: initialized.
229 storeError
OStorePageManager::iget (
230 OStoreDirectoryPageObject
& rPage
,
232 const rtl_String
* pPath
,
233 const rtl_String
* pName
,
234 storeAccessMode eMode
)
236 // Acquire exclusive access.
237 osl::MutexGuard
aGuard(*this);
240 if (!self::isValid())
241 return store_E_InvalidAccess
;
243 // Setup inode page key.
245 storeError eErrCode
= namei (pPath
, pName
, aKey
);
246 if (eErrCode
!= store_E_None
)
249 // Check for directory.
250 if (nAttrib
& STORE_ATTRIB_ISDIR
)
252 // Ugly, but necessary (backward compatibility).
253 aKey
.m_nLow
= store::htonl(rtl_crc32 (store::ntohl(aKey
.m_nLow
), "/", 1));
257 eErrCode
= load_dirpage_Impl (aKey
, rPage
);
258 if (eErrCode
!= store_E_None
)
260 // Check mode and reason.
261 if (eErrCode
!= store_E_NotExists
)
264 if (eMode
== storeAccessMode::ReadWrite
)
265 return store_E_NotExists
;
266 if (eMode
== storeAccessMode::ReadOnly
)
267 return store_E_NotExists
;
269 if (!base::isWriteable())
270 return store_E_AccessViolation
;
272 // Create inode page.
273 eErrCode
= rPage
.construct
< inode
>(base::allocator());
274 if (eErrCode
!= store_E_None
)
277 // Setup inode nameblock.
278 PageHolderObject
< inode
> xPage (rPage
.get());
281 rPage
.attrib (nAttrib
);
284 &(xPage
->m_aNameBlock
.m_pData
[0]),
285 pName
->buffer
, pName
->length
);
288 eErrCode
= save_dirpage_Impl (aKey
, rPage
);
289 if (eErrCode
!= store_E_None
)
293 // Check for symbolic link.
294 if (rPage
.attrib() & STORE_ATTRIB_ISLINK
)
296 // Obtain 'Destination' page key.
297 PageHolderObject
< inode
> xPage (rPage
.get());
298 OStorePageKey aDstKey
;
299 memcpy (&aDstKey
, &(xPage
->m_pData
[0]), sizeof(aDstKey
));
301 // Load 'Destination' inode.
302 eErrCode
= load_dirpage_Impl (aDstKey
, rPage
);
303 if (eErrCode
!= store_E_None
)
313 * Precond: initialized.
314 * ToDo: skip hardlink entries.
316 storeError
OStorePageManager::iterate (
317 OStorePageKey
& rKey
,
318 OStorePageLink
& rLink
,
319 sal_uInt32
& rAttrib
)
321 // Acquire exclusive access.
322 osl::MutexGuard
aGuard(*this);
325 if (!self::isValid())
326 return store_E_InvalidAccess
;
328 // Find NodePage and Index.
329 OStoreBTreeNodeObject aNode
;
331 storeError eErrCode
= m_aRoot
.find_lookup (aNode
, i
, rKey
, *this);
332 if (eErrCode
!= store_E_None
)
335 // GreaterEqual. Found next entry.
336 PageHolderObject
< page
> xNode (aNode
.get());
337 entry
e (xNode
->m_pData
[i
]);
342 rAttrib
= store::ntohl(e
.m_nAttrib
);
349 * load => private: iget() @@@
350 * Internal: Precond: initialized, exclusive access.
352 storeError
OStorePageManager::load_dirpage_Impl (
353 const OStorePageKey
&rKey
,
354 OStoreDirectoryPageObject
&rPage
)
356 // Find Node and Index.
357 OStoreBTreeNodeObject aNode
;
359 storeError eErrCode
= find_lookup (aNode
, i
, rKey
);
360 if (eErrCode
!= store_E_None
)
363 // Existing entry. Load page.
364 PageHolderObject
< page
> xNode (aNode
.get());
365 entry
e (xNode
->m_pData
[i
]);
366 return loadObjectAt (rPage
, e
.m_aLink
.location());
370 * save => private: iget(), rebuild() @@@
371 * Internal: Precond: initialized, writeable, exclusive access.
373 storeError
OStorePageManager::save_dirpage_Impl (
374 const OStorePageKey
&rKey
,
375 OStoreDirectoryPageObject
&rPage
)
377 // Find NodePage and Index.
381 storeError eErrCode
= m_aRoot
.find_insert (aNode
, i
, rKey
, *this);
382 PageHolderObject
< page
> xNode (aNode
.get());
383 if (eErrCode
!= store_E_None
)
385 if (eErrCode
!= store_E_AlreadyExists
)
389 entry
e (xNode
->m_pData
[i
]);
390 if (e
.m_aLink
.location() != STORE_PAGE_NULL
)
392 // Save page to existing location.
393 return saveObjectAt (rPage
, e
.m_aLink
.location());
397 eErrCode
= base::allocate (rPage
);
398 if (eErrCode
!= store_E_None
)
401 // Update page location.
402 xNode
->m_pData
[i
].m_aLink
= rPage
.location();
404 // Save modified NodePage.
405 return saveObjectAt (aNode
, aNode
.location());
409 eErrCode
= base::allocate (rPage
);
410 if (eErrCode
!= store_E_None
)
414 OStorePageLink
aLink (rPage
.location());
415 xNode
->insert (i
+ 1, entry (rKey
, aLink
));
417 // Save modified NodePage.
418 return saveObjectAt (aNode
, aNode
.location());
423 * Precond: initialized, writeable.
425 storeError
OStorePageManager::remove (const OStorePageKey
&rKey
)
427 // Acquire exclusive access.
428 osl::MutexGuard
aGuard(*this);
431 if (!self::isValid())
432 return store_E_InvalidAccess
;
434 if (!base::isWriteable())
435 return store_E_AccessViolation
;
437 // Find NodePage and index.
438 OStoreBTreeNodeObject aNodePage
;
440 storeError eErrCode
= find_lookup (aNodePage
, i
, rKey
);
441 if (eErrCode
!= store_E_None
)
445 PageHolderObject
< page
> xNodePage (aNodePage
.get());
446 entry
e (xNodePage
->m_pData
[i
]);
448 // Check for (not a) hardlink.
449 if (!(store::ntohl(e
.m_nAttrib
) & STORE_ATTRIB_ISLINK
))
451 // Load directory page.
452 OStoreDirectoryPageObject aPage
;
453 eErrCode
= base::loadObjectAt (aPage
, e
.m_aLink
.location());
454 if (eErrCode
!= store_E_None
)
457 inode_holder_type
xNode (aPage
.get());
459 // Acquire page write access.
460 OStorePageDescriptor
aDescr (xNode
->m_aDescr
);
461 eErrCode
= base::acquirePage (aDescr
, storeAccessMode::ReadWrite
);
462 if (eErrCode
!= store_E_None
)
465 // Check for symbolic link.
466 if (!(aPage
.attrib() & STORE_ATTRIB_ISLINK
))
468 // Ordinary inode. Determine 'Data' scope.
469 inode::ChunkScope eScope
= xNode
->scope (aPage
.dataLength());
470 if (eScope
== inode::SCOPE_EXTERNAL
)
472 // External 'Data' scope. Truncate all external data pages.
473 eErrCode
= aPage
.truncate (0, *this);
474 if (eErrCode
!= store_E_None
)
478 // Truncate internal data page.
479 memset (&(xNode
->m_pData
[0]), 0, xNode
->capacity());
480 aPage
.dataLength (0);
483 // Release page write access.
484 base::releasePage (aDescr
);
486 // Release and free directory page.
487 (void)base::free (aPage
.location());
491 return remove_Impl (e
);
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */