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 "rtl/ref.hxx"
26 #include "osl/diagnose.h"
27 #include "osl/mutex.hxx"
29 #include "store/types.h"
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);
50 OStorePageManager::OStorePageManager()
57 OStorePageManager::~OStorePageManager()
64 bool OStorePageManager::isKindOf (sal_uInt32 nTypeId
)
66 return (nTypeId
== m_nTypeId
);
70 * initialize (two-phase construction).
73 storeError
OStorePageManager::initialize (
74 ILockBytes
* pLockBytes
,
75 storeAccessMode eAccessMode
,
76 sal_uInt16
& rnPageSize
)
78 // Acquire exclusive access.
79 osl::MutexGuard
aGuard(*this);
83 return store_E_InvalidParameter
;
86 storeError eErrCode
= base::initialize (pLockBytes
, eAccessMode
, rnPageSize
);
87 if (eErrCode
!= store_E_None
)
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
));
109 eErrCode
= base::saveObjectAt (m_aRoot
, rnPageSize
);
117 * find_lookup (w/o split()).
118 * Internal: Precond: initialized, readable, exclusive access.
120 storeError
OStorePageManager::find_lookup (
121 OStoreBTreeNodeObject
& rNode
,
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
)
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
)
139 return store_E_NotExists
;
143 if (e
.m_aLink
.location() == STORE_PAGE_NULL
)
146 return store_E_NotExists
;
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();
166 // Path to entry not exists (Must not happen(?)).
167 return store_E_NotExists
;
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
;
185 storeError eErrCode
= loadObjectAt (aNode
, nAddr
);
186 if (eErrCode
!= store_E_None
)
189 PageHolderObject
< page
> xNext (aNode
.get());
193 i
= xPage
->find (rEntry
);
194 n
= xPage
->usageCount();
197 // Path to entry not exists (Must not happen(?)).
198 return store_E_NotExists
;
202 result
= rEntry
.compare (xPage
->m_pData
[i
]);
206 result
== entry::COMPARE_LESS
,
208 "OStorePageManager::remove(): find failed");
210 // Check entry comparison.
211 if (result
== entry::COMPARE_LESS
)
214 return store_E_Unknown
;
217 // Remove down from current page (recursive).
218 return aNode
.remove (i
, rEntry
, *this);
223 * Precond: none (static).
225 storeError
OStorePageManager::namei (
226 const rtl_String
*pPath
, const rtl_String
*pName
, OStorePageKey
&rKey
)
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
));
246 * Precond: initialized.
248 storeError
OStorePageManager::iget (
249 OStoreDirectoryPageObject
& rPage
,
251 const rtl_String
* pPath
,
252 const rtl_String
* pName
,
253 storeAccessMode eMode
)
255 // Acquire exclusive access.
256 osl::MutexGuard
aGuard(*this);
259 if (!self::isValid())
260 return store_E_InvalidAccess
;
262 // Setup inode page key.
264 storeError eErrCode
= namei (pPath
, pName
, aKey
);
265 if (eErrCode
!= store_E_None
)
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));
276 eErrCode
= load_dirpage_Impl (aKey
, rPage
);
277 if (eErrCode
!= store_E_None
)
279 // Check mode and reason.
280 if (eErrCode
!= store_E_NotExists
)
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
)
296 // Setup inode nameblock.
297 PageHolderObject
< inode
> xPage (rPage
.get());
300 rPage
.attrib (nAttrib
);
303 &(xPage
->m_aNameBlock
.m_pData
[0]),
304 pName
->buffer
, pName
->length
);
307 eErrCode
= save_dirpage_Impl (aKey
, rPage
);
308 if (eErrCode
!= store_E_None
)
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
)
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);
344 if (!self::isValid())
345 return store_E_InvalidAccess
;
347 // Find NodePage and Index.
348 OStoreBTreeNodeObject aNode
;
350 storeError eErrCode
= m_aRoot
.find_lookup (aNode
, i
, rKey
, *this);
351 if (eErrCode
!= store_E_None
)
354 // GreaterEqual. Found next entry.
355 PageHolderObject
< page
> xNode (aNode
.get());
356 entry
e (xNode
->m_pData
[i
]);
361 rAttrib
= store::ntohl(e
.m_nAttrib
);
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
;
378 storeError eErrCode
= find_lookup (aNode
, i
, rKey
);
379 if (eErrCode
!= store_E_None
)
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.
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
)
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());
416 eErrCode
= base::allocate (rPage
);
417 if (eErrCode
!= store_E_None
)
420 // Update page location.
421 xNode
->m_pData
[i
].m_aLink
= rPage
.location();
423 // Save modified NodePage.
424 return saveObjectAt (aNode
, aNode
.location());
428 eErrCode
= base::allocate (rPage
);
429 if (eErrCode
!= store_E_None
)
433 OStorePageLink
aLink (rPage
.location());
434 xNode
->insert (i
+ 1, entry (rKey
, aLink
));
436 // Save modified NodePage.
437 return saveObjectAt (aNode
, aNode
.location());
442 * Precond: initialized, writeable.
444 storeError
OStorePageManager::remove (const OStorePageKey
&rKey
)
446 // Acquire exclusive access.
447 osl::MutexGuard
aGuard(*this);
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
;
459 storeError eErrCode
= find_lookup (aNodePage
, i
, rKey
);
460 if (eErrCode
!= store_E_None
)
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
)
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
)
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
)
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());
510 return remove_Impl (e
);
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */