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