Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "storlckb.hxx"
21 :
22 : #include "sal/types.h"
23 : #include "sal/macros.h"
24 : #include "rtl/string.h"
25 : #include "rtl/ref.hxx"
26 : #include "osl/mutex.hxx"
27 :
28 : #include "store/types.h"
29 : #include "object.hxx"
30 :
31 : #include "storbase.hxx"
32 : #include "stordata.hxx"
33 : #include "storpage.hxx"
34 :
35 : using namespace store;
36 :
37 : /*========================================================================
38 : *
39 : * OStoreLockBytes implementation.
40 : *
41 : *======================================================================*/
42 : const sal_uInt32 OStoreLockBytes::m_nTypeId = sal_uInt32(0x94190310);
43 :
44 : /*
45 : * OStoreLockBytes.
46 : */
47 0 : OStoreLockBytes::OStoreLockBytes (void)
48 : : m_xManager (),
49 : m_xNode (),
50 0 : m_bWriteable (false)
51 : {
52 0 : }
53 :
54 : /*
55 : * ~OStoreLockBytes.
56 : */
57 0 : OStoreLockBytes::~OStoreLockBytes (void)
58 : {
59 0 : if (m_xManager.is() && m_xNode.is())
60 : {
61 0 : m_xManager->releasePage(m_xNode->m_aDescr);
62 : }
63 0 : }
64 :
65 : /*
66 : * isKindOf.
67 : */
68 0 : bool OStoreLockBytes::isKindOf (sal_uInt32 nTypeId)
69 : {
70 0 : return (nTypeId == m_nTypeId);
71 : }
72 :
73 : /*
74 : * create.
75 : */
76 0 : storeError OStoreLockBytes::create (
77 : OStorePageManager *pManager,
78 : rtl_String *pPath,
79 : rtl_String *pName,
80 : storeAccessMode eMode)
81 : {
82 0 : rtl::Reference<OStorePageManager> xManager (pManager);
83 0 : if (!xManager.is())
84 0 : return store_E_InvalidAccess;
85 :
86 0 : if (!(pPath && pName))
87 0 : return store_E_InvalidParameter;
88 :
89 0 : OStoreDirectoryPageObject aPage;
90 : storeError eErrCode = xManager->iget (
91 : aPage, STORE_ATTRIB_ISFILE,
92 0 : pPath, pName, eMode);
93 0 : if (eErrCode != store_E_None)
94 0 : return eErrCode;
95 :
96 0 : if (!(aPage.attrib() & STORE_ATTRIB_ISFILE))
97 : {
98 : // No ISFILE in older versions (backward compatibility).
99 0 : if (aPage.attrib() & STORE_ATTRIB_ISLINK)
100 0 : return store_E_NotFile;
101 : }
102 :
103 0 : inode_holder_type xNode (aPage.get());
104 0 : if (eMode != store_AccessReadOnly)
105 0 : eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadWrite);
106 : else
107 0 : eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly);
108 0 : if (eErrCode != store_E_None)
109 0 : return eErrCode;
110 :
111 0 : m_xManager = xManager;
112 0 : m_xNode = xNode;
113 0 : m_bWriteable = (eMode != store_AccessReadOnly);
114 :
115 : // Check for truncation.
116 0 : if (eMode == store_AccessCreate)
117 : {
118 : // Truncate to zero length.
119 0 : eErrCode = setSize(0);
120 : }
121 0 : return eErrCode;
122 : }
123 :
124 : /*
125 : * readAt.
126 : */
127 0 : storeError OStoreLockBytes::readAt (
128 : sal_uInt32 nOffset,
129 : void *pBuffer,
130 : sal_uInt32 nBytes,
131 : sal_uInt32 &rnDone)
132 : {
133 0 : rnDone = 0;
134 :
135 0 : if (!m_xManager.is())
136 0 : return store_E_InvalidAccess;
137 :
138 0 : if (!pBuffer)
139 0 : return store_E_InvalidParameter;
140 0 : if (!nBytes)
141 0 : return store_E_None;
142 :
143 : // Acquire exclusive access.
144 0 : osl::MutexGuard aGuard (*m_xManager);
145 :
146 : // Determine data length.
147 0 : OStoreDirectoryPageObject aPage (m_xNode.get());
148 :
149 0 : sal_uInt32 nDataLen = aPage.dataLength();
150 0 : if ((nOffset + nBytes) > nDataLen)
151 0 : nBytes = nDataLen - nOffset;
152 :
153 : // Read data.
154 0 : OStoreDataPageObject aData;
155 0 : sal_uInt8 *pData = (sal_uInt8*)pBuffer;
156 0 : while ((0 < nBytes) && (nOffset < nDataLen))
157 : {
158 : // Determine 'Offset' scope.
159 0 : inode::ChunkScope eScope = m_xNode->scope (nOffset);
160 0 : if (eScope == inode::SCOPE_INTERNAL)
161 : {
162 : // Read from inode page (internal scope).
163 : inode::ChunkDescriptor aDescr (
164 0 : nOffset, m_xNode->capacity());
165 :
166 0 : sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
167 0 : if(nLength > nBytes)
168 : {
169 0 : nLength = nBytes;
170 : }
171 : memcpy (
172 0 : &pData[rnDone],
173 0 : &m_xNode->m_pData[aDescr.m_nOffset],
174 0 : nLength);
175 :
176 : // Adjust counters.
177 0 : rnDone += nLength;
178 0 : nOffset += nLength;
179 0 : nBytes -= nLength;
180 : }
181 : else
182 : {
183 : // Read from data page (external scope).
184 : inode::ChunkDescriptor aDescr (
185 0 : nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@
186 :
187 0 : sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
188 0 : if(nLength > nBytes)
189 : {
190 0 : nLength = nBytes;
191 : }
192 :
193 0 : storeError eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager);
194 0 : if (eErrCode != store_E_None)
195 : {
196 0 : if (eErrCode != store_E_NotExists)
197 0 : return eErrCode;
198 :
199 : memset (
200 0 : &pData[rnDone],
201 : 0,
202 0 : nLength);
203 : }
204 : else
205 : {
206 0 : PageHolderObject< data > xData (aData.makeHolder<data>());
207 : memcpy (
208 0 : &pData[rnDone],
209 0 : &xData->m_pData[aDescr.m_nOffset],
210 0 : nLength);
211 : }
212 :
213 : // Adjust counters.
214 0 : rnDone += nLength;
215 0 : nOffset += nLength;
216 0 : nBytes -= nLength;
217 : }
218 : }
219 :
220 : // Done.
221 0 : return store_E_None;
222 : }
223 :
224 : /*
225 : * writeAt.
226 : */
227 0 : storeError OStoreLockBytes::writeAt (
228 : sal_uInt32 nOffset,
229 : const void *pBuffer,
230 : sal_uInt32 nBytes,
231 : sal_uInt32 &rnDone)
232 : {
233 0 : rnDone = 0;
234 :
235 0 : if (!m_xManager.is())
236 0 : return store_E_InvalidAccess;
237 0 : if (!m_bWriteable)
238 0 : return store_E_AccessViolation;
239 :
240 0 : if (!pBuffer)
241 0 : return store_E_InvalidParameter;
242 0 : if (!nBytes)
243 0 : return store_E_None;
244 :
245 : // Acquire exclusive access.
246 0 : osl::MutexGuard aGuard (*m_xManager);
247 :
248 : // Write data.
249 0 : OStoreDirectoryPageObject aPage (m_xNode.get());
250 0 : const sal_uInt8 *pData = (const sal_uInt8*)pBuffer;
251 :
252 0 : storeError eErrCode = store_E_None;
253 0 : while (nBytes > 0)
254 : {
255 : // Determine 'Offset' scope.
256 0 : inode::ChunkScope eScope = m_xNode->scope (nOffset);
257 0 : if (eScope == inode::SCOPE_INTERNAL)
258 : {
259 : // Write to inode page (internal scope).
260 : inode::ChunkDescriptor aDescr (
261 0 : nOffset, m_xNode->capacity());
262 :
263 0 : sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
264 0 : if(nLength > nBytes)
265 : {
266 0 : nLength = nBytes;
267 : }
268 :
269 : memcpy (
270 0 : &m_xNode->m_pData[aDescr.m_nOffset],
271 0 : &pData[rnDone], nLength);
272 :
273 : // Mark inode dirty.
274 0 : aPage.touch();
275 :
276 : // Adjust counters.
277 0 : rnDone += nLength;
278 0 : nOffset += nLength;
279 0 : nBytes -= nLength;
280 :
281 : // Adjust data length.
282 0 : if (aPage.dataLength() < nOffset)
283 0 : aPage.dataLength (nOffset);
284 : }
285 : else
286 : {
287 : // Write to data page (external scope).
288 0 : OStoreDataPageObject aData;
289 :
290 : inode::ChunkDescriptor aDescr (
291 0 : nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@
292 :
293 0 : sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
294 0 : if ((aDescr.m_nOffset > 0) || (nBytes < nLength))
295 : {
296 : // Unaligned. Need to load/create data page.
297 : // @@@ loadOrCreate()
298 0 : eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager);
299 0 : if (eErrCode != store_E_None)
300 : {
301 0 : if (eErrCode != store_E_NotExists)
302 0 : return eErrCode;
303 :
304 0 : eErrCode = aData.construct<data>(m_xManager->allocator());
305 0 : if (eErrCode != store_E_None)
306 0 : return eErrCode;
307 : }
308 : }
309 :
310 0 : PageHolderObject< data > xData (aData.makeHolder<data>());
311 0 : if (!xData.is())
312 : {
313 0 : eErrCode = aData.construct<data>(m_xManager->allocator());
314 0 : if (eErrCode != store_E_None)
315 0 : return eErrCode;
316 0 : xData = aData.makeHolder<data>();
317 : }
318 :
319 : // Modify data page.
320 0 : if(nLength > nBytes)
321 : {
322 0 : nLength = nBytes;
323 : }
324 : memcpy (
325 0 : &xData->m_pData[aDescr.m_nOffset],
326 0 : &pData[rnDone], nLength);
327 :
328 : // Save data page.
329 0 : eErrCode = aPage.write (aDescr.m_nPage, aData, *m_xManager);
330 0 : if (eErrCode != store_E_None)
331 0 : return eErrCode;
332 :
333 : // Adjust counters.
334 0 : rnDone += nLength;
335 0 : nOffset += nLength;
336 0 : nBytes -= nLength;
337 :
338 : // Adjust data length.
339 0 : if (aPage.dataLength() < nOffset)
340 0 : aPage.dataLength (nOffset);
341 : }
342 : }
343 :
344 : // Check for modified inode.
345 0 : if (aPage.dirty())
346 0 : return m_xManager->saveObjectAt (aPage, aPage.location());
347 : else
348 0 : return store_E_None;
349 : }
350 :
351 : /*
352 : * flush.
353 : */
354 0 : storeError OStoreLockBytes::flush (void)
355 : {
356 0 : if (!m_xManager.is())
357 0 : return store_E_InvalidAccess;
358 :
359 0 : return m_xManager->flush();
360 : }
361 :
362 : /*
363 : * setSize.
364 : */
365 0 : storeError OStoreLockBytes::setSize (sal_uInt32 nSize)
366 : {
367 0 : if (!m_xManager.is())
368 0 : return store_E_InvalidAccess;
369 0 : if (!m_bWriteable)
370 0 : return store_E_AccessViolation;
371 :
372 : // Acquire exclusive access.
373 0 : osl::MutexGuard aGuard (*m_xManager);
374 :
375 : // Determine current length.
376 0 : OStoreDirectoryPageObject aPage (m_xNode.get());
377 0 : sal_uInt32 nDataLen = aPage.dataLength();
378 :
379 0 : if (nSize == nDataLen)
380 0 : return store_E_None;
381 :
382 0 : if (nSize < nDataLen)
383 : {
384 : // Truncate.
385 0 : storeError eErrCode = store_E_None;
386 :
387 : // Determine 'Size' scope.
388 0 : inode::ChunkScope eSizeScope = m_xNode->scope (nSize);
389 0 : if (eSizeScope == inode::SCOPE_INTERNAL)
390 : {
391 : // Internal 'Size' scope. Determine 'Data' scope.
392 0 : inode::ChunkScope eDataScope = m_xNode->scope (nDataLen);
393 0 : if (eDataScope == inode::SCOPE_EXTERNAL)
394 : {
395 : // External 'Data' scope. Truncate all external data pages.
396 0 : eErrCode = aPage.truncate (0, *m_xManager);
397 0 : if (eErrCode != store_E_None)
398 0 : return eErrCode;
399 : }
400 :
401 : // Truncate internal data page.
402 0 : inode::ChunkDescriptor aDescr (nSize, m_xNode->capacity());
403 : memset (
404 0 : &(m_xNode->m_pData[aDescr.m_nOffset]),
405 0 : 0, aDescr.m_nLength);
406 : }
407 : else
408 : {
409 : // External 'Size' scope. Truncate external data pages.
410 : inode::ChunkDescriptor aDescr (
411 0 : nSize - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@
412 :
413 0 : sal_uInt32 nPage = aDescr.m_nPage;
414 0 : if (aDescr.m_nOffset) nPage += 1;
415 :
416 0 : eErrCode = aPage.truncate (nPage, *m_xManager);
417 0 : if (eErrCode != store_E_None)
418 0 : return eErrCode;
419 : }
420 : }
421 :
422 : // Set (extended or truncated) size.
423 0 : aPage.dataLength (nSize);
424 :
425 : // Save modified inode.
426 0 : return m_xManager->saveObjectAt (aPage, aPage.location());
427 : }
428 :
429 : /*
430 : * stat.
431 : */
432 0 : storeError OStoreLockBytes::stat (sal_uInt32 &rnSize)
433 : {
434 0 : rnSize = 0;
435 :
436 0 : if (!m_xManager.is())
437 0 : return store_E_InvalidAccess;
438 :
439 0 : OStoreDirectoryPageObject aPage (m_xNode.get());
440 0 : rnSize = aPage.dataLength();
441 0 : return store_E_None;
442 : }
443 :
444 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|