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 "lockbyte.hxx"
21 :
22 : #include "boost/noncopyable.hpp"
23 : #include "sal/types.h"
24 : #include "osl/diagnose.h"
25 : #include "osl/file.h"
26 : #include "osl/process.h"
27 : #include "rtl/alloc.h"
28 : #include "rtl/ustring.hxx"
29 : #include "sal/log.hxx"
30 :
31 : #include "object.hxx"
32 : #include "storbase.hxx"
33 :
34 : #include <string.h>
35 :
36 : using namespace store;
37 :
38 : /*========================================================================
39 : *
40 : * ILockBytes (non-virtual interface) implementation.
41 : *
42 : *======================================================================*/
43 :
44 148 : storeError ILockBytes::initialize (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
45 : {
46 : OSL_PRECOND((STORE_MINIMUM_PAGESIZE <= nPageSize) && (nPageSize <= STORE_MAXIMUM_PAGESIZE), "invalid PageSize");
47 148 : return initialize_Impl (rxAllocator, nPageSize);
48 : }
49 :
50 148 : storeError ILockBytes::readPageAt (PageHolder & rPage, sal_uInt32 nOffset)
51 : {
52 : OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readPageAt(): invalid Offset");
53 148 : if (nOffset == STORE_PAGE_NULL)
54 0 : return store_E_CantSeek;
55 :
56 148 : return readPageAt_Impl (rPage, nOffset);
57 : }
58 :
59 2740 : storeError ILockBytes::writePageAt (PageHolder const & rPage, sal_uInt32 nOffset)
60 : {
61 : // [SECURITY:ValInput]
62 2740 : PageData const * pagedata = rPage.get();
63 : OSL_PRECOND(!(pagedata == 0), "store::ILockBytes::writePageAt(): invalid Page");
64 2740 : if (pagedata == 0)
65 0 : return store_E_InvalidParameter;
66 :
67 2740 : sal_uInt32 const offset = pagedata->location();
68 : OSL_PRECOND(!(nOffset != offset), "store::ILockBytes::writePageAt(): inconsistent Offset");
69 2740 : if (nOffset != offset)
70 0 : return store_E_InvalidParameter;
71 :
72 : OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writePageAt(): invalid Offset");
73 2740 : if (nOffset == STORE_PAGE_NULL)
74 0 : return store_E_CantSeek;
75 :
76 2740 : return writePageAt_Impl (rPage, nOffset);
77 : }
78 :
79 12 : storeError ILockBytes::readAt (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
80 : {
81 : // [SECURITY:ValInput]
82 12 : sal_uInt8 * dst_lo = static_cast<sal_uInt8*>(pBuffer);
83 12 : if (!(dst_lo != 0))
84 0 : return store_E_InvalidParameter;
85 :
86 12 : sal_uInt8 * dst_hi = dst_lo + nBytes;
87 12 : if (!(dst_lo < dst_hi))
88 0 : return (dst_lo > dst_hi) ? store_E_InvalidParameter : store_E_None;
89 :
90 : OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::readAt(): invalid Offset");
91 12 : if (nOffset == STORE_PAGE_NULL)
92 0 : return store_E_CantSeek;
93 :
94 12 : sal_uInt64 const src_size = static_cast<sal_uInt64>(nOffset) + nBytes;
95 12 : if (src_size > SAL_MAX_UINT32)
96 0 : return store_E_CantSeek;
97 :
98 12 : return readAt_Impl (nOffset, dst_lo, (dst_hi - dst_lo));
99 : }
100 :
101 168 : storeError ILockBytes::writeAt (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes)
102 : {
103 : // [SECURITY:ValInput]
104 168 : sal_uInt8 const * src_lo = static_cast<sal_uInt8 const*>(pBuffer);
105 168 : if (!(src_lo != 0))
106 0 : return store_E_InvalidParameter;
107 :
108 168 : sal_uInt8 const * src_hi = src_lo + nBytes;
109 168 : if (!(src_lo < src_hi))
110 0 : return (src_lo > src_hi) ? store_E_InvalidParameter : store_E_None;
111 :
112 : OSL_PRECOND(!(nOffset == STORE_PAGE_NULL), "store::ILockBytes::writeAt(): invalid Offset");
113 168 : if (nOffset == STORE_PAGE_NULL)
114 0 : return store_E_CantSeek;
115 :
116 168 : sal_uInt64 const dst_size = static_cast<sal_uInt64>(nOffset) + nBytes;
117 168 : if (dst_size > SAL_MAX_UINT32)
118 0 : return store_E_CantSeek;
119 :
120 168 : return writeAt_Impl (nOffset, src_lo, (src_hi - src_lo));
121 : }
122 :
123 1226 : storeError ILockBytes::getSize (sal_uInt32 & rnSize)
124 : {
125 1226 : rnSize = 0;
126 1226 : return getSize_Impl (rnSize);
127 : }
128 :
129 148 : storeError ILockBytes::setSize (sal_uInt32 nSize)
130 : {
131 148 : return setSize_Impl (nSize);
132 : }
133 :
134 2 : storeError ILockBytes::flush()
135 : {
136 2 : return flush_Impl();
137 : }
138 :
139 : /*========================================================================
140 : *
141 : * FileLockBytes implementation.
142 : *
143 : *======================================================================*/
144 : namespace store
145 : {
146 :
147 : struct FileHandle
148 : {
149 : oslFileHandle m_handle;
150 :
151 448 : FileHandle() : m_handle(0) {}
152 :
153 150 : bool operator != (FileHandle const & rhs)
154 : {
155 150 : return (m_handle != rhs.m_handle);
156 : }
157 :
158 2 : static storeError errorFromNative (oslFileError eErrno)
159 : {
160 2 : switch (eErrno)
161 : {
162 : case osl_File_E_None:
163 0 : return store_E_None;
164 :
165 : case osl_File_E_NOENT:
166 2 : return store_E_NotExists;
167 :
168 : case osl_File_E_ACCES:
169 : case osl_File_E_PERM:
170 0 : return store_E_AccessViolation;
171 :
172 : case osl_File_E_AGAIN:
173 : case osl_File_E_DEADLK:
174 0 : return store_E_LockingViolation;
175 :
176 : case osl_File_E_BADF:
177 0 : return store_E_InvalidHandle;
178 :
179 : case osl_File_E_INVAL:
180 0 : return store_E_InvalidParameter;
181 :
182 : case osl_File_E_NOMEM:
183 0 : return store_E_OutOfMemory;
184 :
185 : case osl_File_E_NOSPC:
186 0 : return store_E_OutOfSpace;
187 :
188 : case osl_File_E_OVERFLOW:
189 0 : return store_E_CantSeek;
190 :
191 : default:
192 0 : return store_E_Unknown;
193 : }
194 : }
195 :
196 150 : static sal_uInt32 modeToNative (storeAccessMode eAccessMode)
197 : {
198 150 : sal_uInt32 nFlags = 0;
199 150 : switch (eAccessMode)
200 : {
201 : case store_AccessCreate:
202 : case store_AccessReadCreate:
203 146 : nFlags |= osl_File_OpenFlag_Create;
204 : // fall through
205 : case store_AccessReadWrite:
206 148 : nFlags |= osl_File_OpenFlag_Write;
207 : // fall through
208 : case store_AccessReadOnly:
209 150 : nFlags |= osl_File_OpenFlag_Read;
210 150 : break;
211 : default:
212 : OSL_PRECOND(false, "store::FileHandle: unknown storeAccessMode");
213 : }
214 150 : return nFlags;
215 : }
216 :
217 150 : storeError initialize (rtl_uString * pFilename, storeAccessMode eAccessMode)
218 : {
219 : // Verify arguments.
220 150 : sal_uInt32 nFlags = modeToNative (eAccessMode);
221 150 : if (!pFilename || !nFlags)
222 0 : return store_E_InvalidParameter;
223 :
224 : // Convert into FileUrl.
225 150 : OUString aFileUrl;
226 150 : if (osl_getFileURLFromSystemPath (pFilename, &(aFileUrl.pData)) != osl_File_E_None)
227 : {
228 : // Not system path. Assume file url.
229 150 : rtl_uString_assign (&(aFileUrl.pData), pFilename);
230 : }
231 150 : if (!aFileUrl.startsWith("file://"))
232 : {
233 : // Not file url. Assume relative path.
234 0 : OUString aCwdUrl;
235 0 : (void) osl_getProcessWorkingDir (&(aCwdUrl.pData));
236 :
237 : // Absolute file url.
238 0 : (void) osl_getAbsoluteFileURL (aCwdUrl.pData, aFileUrl.pData, &(aFileUrl.pData));
239 : }
240 :
241 : // Acquire handle.
242 150 : oslFileError result = osl_openFile (aFileUrl.pData, &m_handle, nFlags);
243 150 : if (result == osl_File_E_EXIST)
244 : {
245 : // Already existing (O_CREAT | O_EXCL).
246 0 : result = osl_openFile (aFileUrl.pData, &m_handle, osl_File_OpenFlag_Read | osl_File_OpenFlag_Write);
247 0 : if ((result == osl_File_E_None) && (eAccessMode == store_AccessCreate))
248 : {
249 : // Truncate existing file.
250 0 : result = osl_setFileSize (m_handle, 0);
251 : }
252 : }
253 150 : if (result != osl_File_E_None)
254 2 : return errorFromNative(result);
255 148 : return store_E_None;
256 : }
257 :
258 : /** @see FileLockBytes destructor
259 : */
260 148 : static void closeFile (oslFileHandle hFile)
261 : {
262 148 : (void) osl_closeFile (hFile);
263 148 : }
264 :
265 : /** @see ResourceHolder<T>::destructor_type
266 : */
267 : struct CloseFile
268 : {
269 0 : void operator()(FileHandle & rFile) const
270 : {
271 : // Release handle.
272 0 : closeFile (rFile.m_handle);
273 0 : rFile.m_handle = 0;
274 0 : }
275 : };
276 : typedef CloseFile destructor_type;
277 : };
278 :
279 : class FileLockBytes :
280 : public store::OStoreObject,
281 : public store::ILockBytes,
282 : private boost::noncopyable
283 : {
284 : /** Representation.
285 : */
286 : oslFileHandle m_hFile;
287 : sal_uInt32 m_nSize;
288 : rtl::Reference< PageData::Allocator > m_xAllocator;
289 :
290 : storeError initSize_Impl (sal_uInt32 & rnSize);
291 :
292 : /** ILockBytes implementation.
293 : */
294 : virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) SAL_OVERRIDE;
295 :
296 : virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) SAL_OVERRIDE;
297 : virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) SAL_OVERRIDE;
298 :
299 : virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) SAL_OVERRIDE;
300 : virtual storeError writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes) SAL_OVERRIDE;
301 :
302 : virtual storeError getSize_Impl (sal_uInt32 & rnSize) SAL_OVERRIDE;
303 : virtual storeError setSize_Impl (sal_uInt32 nSize) SAL_OVERRIDE;
304 :
305 : virtual storeError flush_Impl() SAL_OVERRIDE;
306 :
307 : public:
308 : /** Construction.
309 : */
310 : explicit FileLockBytes (FileHandle & rFile);
311 :
312 : protected:
313 : /** Destruction.
314 : */
315 : virtual ~FileLockBytes();
316 : };
317 :
318 : } // namespace store
319 :
320 148 : FileLockBytes::FileLockBytes (FileHandle & rFile)
321 148 : : m_hFile (rFile.m_handle), m_nSize (SAL_MAX_UINT32), m_xAllocator()
322 : {
323 148 : }
324 :
325 592 : FileLockBytes::~FileLockBytes()
326 : {
327 148 : FileHandle::closeFile (m_hFile);
328 444 : }
329 :
330 146 : storeError FileLockBytes::initSize_Impl (sal_uInt32 & rnSize)
331 : {
332 : /* osl_getFileSize() uses slow 'fstat(h, &size)',
333 : * instead of fast 'size = lseek(h, 0, SEEK_END)'.
334 : * so, init size here, and track changes.
335 : */
336 146 : sal_uInt64 uSize = 0;
337 146 : oslFileError result = osl_getFileSize (m_hFile, &uSize);
338 146 : if (result != osl_File_E_None)
339 0 : return FileHandle::errorFromNative(result);
340 146 : if (uSize > SAL_MAX_UINT32)
341 0 : return store_E_CantSeek;
342 :
343 146 : rnSize = sal::static_int_cast<sal_uInt32>(uSize);
344 146 : return store_E_None;
345 : }
346 :
347 146 : storeError FileLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
348 : {
349 146 : storeError result = initSize_Impl (m_nSize);
350 146 : if (result != store_E_None)
351 0 : return result;
352 :
353 146 : result = PageData::Allocator::createInstance (rxAllocator, nPageSize);
354 146 : if (result != store_E_None)
355 0 : return result;
356 :
357 : // @see readPageAt_Impl().
358 146 : m_xAllocator = rxAllocator;
359 146 : return store_E_None;
360 : }
361 :
362 146 : storeError FileLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset)
363 : {
364 146 : if (m_xAllocator.is())
365 : {
366 146 : PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator);
367 146 : page.swap (rPage);
368 : }
369 :
370 146 : if (!m_xAllocator.is())
371 0 : return store_E_InvalidAccess;
372 146 : if (!rPage.get())
373 0 : return store_E_OutOfMemory;
374 :
375 146 : PageData * pagedata = rPage.get();
376 146 : return readAt_Impl (nOffset, pagedata, pagedata->size());
377 : }
378 :
379 2704 : storeError FileLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset)
380 : {
381 2704 : PageData const * pagedata = rPage.get();
382 : OSL_PRECOND(pagedata != 0, "contract violation");
383 2704 : return writeAt_Impl (nOffset, pagedata, pagedata->size());
384 : }
385 :
386 158 : storeError FileLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
387 : {
388 158 : sal_uInt64 nDone = 0;
389 158 : oslFileError result = osl_readFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone);
390 158 : if (result != osl_File_E_None)
391 0 : return FileHandle::errorFromNative(result);
392 158 : if (nDone != nBytes)
393 148 : return (nDone != 0) ? store_E_CantRead : store_E_NotExists;
394 10 : return store_E_None;
395 : }
396 :
397 2870 : storeError FileLockBytes::writeAt_Impl (sal_uInt32 nOffset, void const * pBuffer, sal_uInt32 nBytes)
398 : {
399 2870 : sal_uInt64 nDone = 0;
400 2870 : oslFileError result = osl_writeFileAt (m_hFile, nOffset, pBuffer, nBytes, &nDone);
401 2870 : if (result != osl_File_E_None)
402 0 : return FileHandle::errorFromNative(result);
403 2870 : if (nDone != nBytes)
404 0 : return store_E_CantWrite;
405 :
406 2870 : sal_uInt64 const uSize = nOffset + nBytes;
407 : OSL_PRECOND(uSize < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation");
408 2870 : if (uSize > m_nSize)
409 1355 : m_nSize = sal::static_int_cast<sal_uInt32>(uSize);
410 2870 : return store_E_None;
411 : }
412 :
413 1209 : storeError FileLockBytes::getSize_Impl (sal_uInt32 & rnSize)
414 : {
415 1209 : rnSize = m_nSize;
416 1209 : return store_E_None;
417 : }
418 :
419 146 : storeError FileLockBytes::setSize_Impl (sal_uInt32 nSize)
420 : {
421 146 : oslFileError result = osl_setFileSize (m_hFile, nSize);
422 146 : if (result != osl_File_E_None)
423 0 : return FileHandle::errorFromNative(result);
424 :
425 146 : m_nSize = nSize;
426 146 : return store_E_None;
427 : }
428 :
429 2 : storeError FileLockBytes::flush_Impl()
430 : {
431 2 : oslFileError result = osl_syncFile (m_hFile);
432 2 : if (result != osl_File_E_None)
433 0 : return FileHandle::errorFromNative(result);
434 2 : return store_E_None;
435 : }
436 :
437 : /*========================================================================
438 : *
439 : * MappedLockBytes implementation.
440 : *
441 : *======================================================================*/
442 : namespace store
443 : {
444 :
445 : struct FileMapping
446 : {
447 : sal_uInt8 * m_pAddr;
448 : sal_uInt32 m_nSize;
449 : oslFileHandle m_hFile;
450 :
451 4 : FileMapping() : m_pAddr(0), m_nSize(0), m_hFile(0) {}
452 :
453 2 : bool operator != (FileMapping const & rhs) const
454 : {
455 2 : return ((m_pAddr != rhs.m_pAddr) || (m_nSize != rhs.m_nSize));
456 : }
457 :
458 2 : oslFileError initialize (oslFileHandle hFile)
459 : {
460 : // Determine mapping size.
461 2 : sal_uInt64 uSize = 0;
462 2 : oslFileError result = osl_getFileSize (hFile, &uSize);
463 2 : if (result != osl_File_E_None)
464 0 : return result;
465 :
466 : // [SECURITY:IntOver]
467 2 : if (uSize > SAL_MAX_UINT32)
468 0 : return osl_File_E_OVERFLOW;
469 2 : m_nSize = sal::static_int_cast<sal_uInt32>(uSize);
470 :
471 2 : m_hFile = hFile;
472 :
473 : // Acquire mapping.
474 2 : return osl_mapFile (hFile, reinterpret_cast<void**>(&m_pAddr), m_nSize, 0, osl_File_MapFlag_RandomAccess);
475 : }
476 :
477 : /** @see MappedLockBytes::destructor.
478 : */
479 0 : static void unmapFile (oslFileHandle hFile, sal_uInt8 * pAddr, sal_uInt32 nSize)
480 : {
481 0 : (void) osl_unmapMappedFile (hFile, pAddr, nSize);
482 0 : (void) osl_closeFile (hFile);
483 0 : }
484 :
485 : /** @see ResourceHolder<T>::destructor_type
486 : */
487 : struct UnmapFile
488 : {
489 0 : void operator ()(FileMapping & rMapping) const
490 : {
491 : // Release mapping.
492 0 : unmapFile (rMapping.m_hFile, rMapping.m_pAddr, rMapping.m_nSize);
493 0 : rMapping.m_pAddr = 0, rMapping.m_nSize = 0;
494 0 : }
495 : };
496 : typedef UnmapFile destructor_type;
497 : };
498 :
499 : class MappedLockBytes :
500 : public store::OStoreObject,
501 : public store::PageData::Allocator,
502 : public store::ILockBytes,
503 : private boost::noncopyable
504 : {
505 : /** Representation.
506 : */
507 : sal_uInt8 * m_pData;
508 : sal_uInt32 m_nSize;
509 : sal_uInt16 m_nPageSize;
510 : oslFileHandle m_hFile;
511 :
512 : /** PageData::Allocator implementation.
513 : */
514 : virtual void allocate_Impl (void ** ppPage, sal_uInt16 * pnSize) SAL_OVERRIDE;
515 : virtual void deallocate_Impl (void * pPage) SAL_OVERRIDE;
516 :
517 : /** ILockBytes implementation.
518 : */
519 : virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) SAL_OVERRIDE;
520 :
521 : virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) SAL_OVERRIDE;
522 : virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) SAL_OVERRIDE;
523 :
524 : virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) SAL_OVERRIDE;
525 : virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes) SAL_OVERRIDE;
526 :
527 : virtual storeError getSize_Impl (sal_uInt32 & rnSize) SAL_OVERRIDE;
528 : virtual storeError setSize_Impl (sal_uInt32 nSize) SAL_OVERRIDE;
529 :
530 : virtual storeError flush_Impl() SAL_OVERRIDE;
531 :
532 : public:
533 : /** Construction.
534 : */
535 : explicit MappedLockBytes (FileMapping & rMapping);
536 :
537 : protected:
538 : /* Destruction.
539 : */
540 : virtual ~MappedLockBytes();
541 : };
542 :
543 : } // namespace store
544 :
545 0 : MappedLockBytes::MappedLockBytes (FileMapping & rMapping)
546 0 : : m_pData (rMapping.m_pAddr), m_nSize (rMapping.m_nSize), m_nPageSize(0), m_hFile (rMapping.m_hFile)
547 : {
548 0 : }
549 :
550 0 : MappedLockBytes::~MappedLockBytes()
551 : {
552 0 : FileMapping::unmapFile (m_hFile, m_pData, m_nSize);
553 0 : }
554 :
555 0 : void MappedLockBytes::allocate_Impl (void ** ppPage, sal_uInt16 * pnSize)
556 : {
557 : OSL_PRECOND((ppPage != 0) && (pnSize != 0), "contract violation");
558 0 : if ((ppPage != 0) && (pnSize != 0))
559 0 : *ppPage = 0, *pnSize = m_nPageSize;
560 0 : }
561 :
562 0 : void MappedLockBytes::deallocate_Impl (void * pPage)
563 : {
564 : OSL_PRECOND((m_pData <= pPage) && (pPage < m_pData + m_nSize), "contract violation");
565 : (void)pPage; // UNUSED
566 0 : }
567 :
568 0 : storeError MappedLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
569 : {
570 0 : rxAllocator = this;
571 0 : m_nPageSize = nPageSize;
572 0 : return store_E_None;
573 : }
574 :
575 0 : storeError MappedLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset)
576 : {
577 0 : sal_uInt8 * src_lo = m_pData + nOffset;
578 0 : if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize))
579 0 : return store_E_NotExists;
580 :
581 0 : sal_uInt8 * src_hi = src_lo + m_nPageSize;
582 0 : if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize))
583 0 : return store_E_CantRead;
584 :
585 0 : PageHolder page (reinterpret_cast< PageData* >(src_lo), static_cast< PageData::Allocator* >(this));
586 0 : page.swap (rPage);
587 :
588 0 : return store_E_None;
589 : }
590 :
591 0 : storeError MappedLockBytes::writePageAt_Impl (PageHolder const & /*rPage*/, sal_uInt32 /*nOffset*/)
592 : {
593 0 : return store_E_AccessViolation;
594 : }
595 :
596 0 : storeError MappedLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
597 : {
598 0 : sal_uInt8 const * src_lo = m_pData + nOffset;
599 0 : if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize))
600 0 : return store_E_NotExists;
601 :
602 0 : sal_uInt8 const * src_hi = src_lo + nBytes;
603 0 : if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize))
604 0 : return store_E_CantRead;
605 :
606 0 : memcpy (pBuffer, src_lo, (src_hi - src_lo));
607 0 : return store_E_None;
608 : }
609 :
610 0 : storeError MappedLockBytes::writeAt_Impl (sal_uInt32 /*nOffset*/, void const * /*pBuffer*/, sal_uInt32 /*nBytes*/)
611 : {
612 0 : return store_E_AccessViolation;
613 : }
614 :
615 0 : storeError MappedLockBytes::getSize_Impl (sal_uInt32 & rnSize)
616 : {
617 0 : rnSize = m_nSize;
618 0 : return store_E_None;
619 : }
620 :
621 0 : storeError MappedLockBytes::setSize_Impl (sal_uInt32 /*nSize*/)
622 : {
623 0 : return store_E_AccessViolation;
624 : }
625 :
626 0 : storeError MappedLockBytes::flush_Impl()
627 : {
628 0 : return store_E_None;
629 : }
630 :
631 : /*========================================================================
632 : *
633 : * MemoryLockBytes implementation.
634 : *
635 : *======================================================================*/
636 : namespace store
637 : {
638 :
639 : class MemoryLockBytes :
640 : public store::OStoreObject,
641 : public store::ILockBytes,
642 : private boost::noncopyable
643 : {
644 : /** Representation.
645 : */
646 : sal_uInt8 * m_pData;
647 : sal_uInt32 m_nSize;
648 : rtl::Reference< PageData::Allocator > m_xAllocator;
649 :
650 : /** ILockBytes implementation.
651 : */
652 : virtual storeError initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize) SAL_OVERRIDE;
653 :
654 : virtual storeError readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset) SAL_OVERRIDE;
655 : virtual storeError writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset) SAL_OVERRIDE;
656 :
657 : virtual storeError readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes) SAL_OVERRIDE;
658 : virtual storeError writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes) SAL_OVERRIDE;
659 :
660 : virtual storeError getSize_Impl (sal_uInt32 & rnSize) SAL_OVERRIDE;
661 : virtual storeError setSize_Impl (sal_uInt32 nSize) SAL_OVERRIDE;
662 :
663 : virtual storeError flush_Impl() SAL_OVERRIDE;
664 :
665 : public:
666 : /** Construction.
667 : */
668 : MemoryLockBytes();
669 :
670 : protected:
671 : /** Destruction.
672 : */
673 : virtual ~MemoryLockBytes();
674 : };
675 :
676 : } // namespace store
677 :
678 2 : MemoryLockBytes::MemoryLockBytes()
679 2 : : m_pData (0), m_nSize (0), m_xAllocator()
680 2 : {}
681 :
682 0 : MemoryLockBytes::~MemoryLockBytes()
683 : {
684 0 : rtl_freeMemory (m_pData);
685 0 : }
686 :
687 2 : storeError MemoryLockBytes::initialize_Impl (rtl::Reference< PageData::Allocator > & rxAllocator, sal_uInt16 nPageSize)
688 : {
689 2 : storeError result = PageData::Allocator::createInstance (rxAllocator, nPageSize);
690 2 : if (result == store_E_None)
691 : {
692 : // @see readPageAt_Impl().
693 2 : m_xAllocator = rxAllocator;
694 : }
695 2 : return result;
696 : }
697 :
698 2 : storeError MemoryLockBytes::readPageAt_Impl (PageHolder & rPage, sal_uInt32 nOffset)
699 : {
700 2 : if (m_xAllocator.is())
701 : {
702 2 : PageHolder page (m_xAllocator->construct<PageData>(), m_xAllocator);
703 2 : page.swap (rPage);
704 : }
705 :
706 2 : if (!m_xAllocator.is())
707 0 : return store_E_InvalidAccess;
708 2 : if (!rPage.get())
709 0 : return store_E_OutOfMemory;
710 :
711 2 : PageData * pagedata = rPage.get();
712 2 : return readAt_Impl (nOffset, pagedata, pagedata->size());
713 : }
714 :
715 36 : storeError MemoryLockBytes::writePageAt_Impl (PageHolder const & rPage, sal_uInt32 nOffset)
716 : {
717 36 : PageData const * pagedata = rPage.get();
718 : OSL_PRECOND(!(pagedata == 0), "contract violation");
719 36 : return writeAt_Impl (nOffset, pagedata, pagedata->size());
720 : }
721 :
722 2 : storeError MemoryLockBytes::readAt_Impl (sal_uInt32 nOffset, void * pBuffer, sal_uInt32 nBytes)
723 : {
724 2 : sal_uInt8 const * src_lo = m_pData + nOffset;
725 2 : if ((m_pData > src_lo) || (src_lo >= m_pData + m_nSize))
726 2 : return store_E_NotExists;
727 :
728 0 : sal_uInt8 const * src_hi = src_lo + nBytes;
729 0 : if ((m_pData > src_hi) || (src_hi > m_pData + m_nSize))
730 0 : return store_E_CantRead;
731 :
732 0 : memcpy (pBuffer, src_lo, (src_hi - src_lo));
733 0 : return store_E_None;
734 : }
735 :
736 38 : storeError MemoryLockBytes::writeAt_Impl (sal_uInt32 nOffset, const void * pBuffer, sal_uInt32 nBytes)
737 : {
738 38 : sal_uInt64 const dst_size = nOffset + nBytes;
739 : OSL_PRECOND(dst_size < SAL_MAX_UINT32, "store::ILockBytes::writeAt() contract violation");
740 38 : if (dst_size > m_nSize)
741 : {
742 19 : storeError eErrCode = setSize_Impl (sal::static_int_cast<sal_uInt32>(dst_size));
743 19 : if (eErrCode != store_E_None)
744 0 : return eErrCode;
745 : }
746 : SAL_WARN_IF(dst_size > m_nSize, "store", "store::MemoryLockBytes::setSize_Impl() contract violation");
747 :
748 38 : sal_uInt8 * dst_lo = m_pData + nOffset;
749 38 : if (dst_lo >= m_pData + m_nSize)
750 0 : return store_E_CantSeek;
751 :
752 38 : sal_uInt8 * dst_hi = dst_lo + nBytes;
753 38 : if (dst_hi > m_pData + m_nSize)
754 0 : return store_E_CantWrite;
755 :
756 38 : memcpy (dst_lo, pBuffer, (dst_hi - dst_lo));
757 38 : return store_E_None;
758 : }
759 :
760 17 : storeError MemoryLockBytes::getSize_Impl (sal_uInt32 & rnSize)
761 : {
762 17 : rnSize = m_nSize;
763 17 : return store_E_None;
764 : }
765 :
766 21 : storeError MemoryLockBytes::setSize_Impl (sal_uInt32 nSize)
767 : {
768 21 : if (nSize != m_nSize)
769 : {
770 19 : sal_uInt8 * pData = static_cast<sal_uInt8*>(rtl_reallocateMemory (m_pData, nSize));
771 19 : if (pData != 0)
772 : {
773 19 : if (nSize > m_nSize)
774 19 : memset (pData + m_nSize, 0, sal::static_int_cast<size_t>(nSize - m_nSize));
775 : }
776 : else
777 : {
778 0 : if (nSize != 0)
779 0 : return store_E_OutOfMemory;
780 : }
781 19 : m_pData = pData, m_nSize = nSize;
782 : }
783 21 : return store_E_None;
784 : }
785 :
786 0 : storeError MemoryLockBytes::flush_Impl()
787 : {
788 0 : return store_E_None;
789 : }
790 :
791 : /*========================================================================
792 : *
793 : * ILockBytes factory implementations.
794 : *
795 : *======================================================================*/
796 : namespace store
797 : {
798 :
799 : template< class T > struct ResourceHolder
800 : {
801 : typedef typename T::destructor_type destructor_type;
802 :
803 : T m_value;
804 :
805 152 : explicit ResourceHolder (T const & value = T()) : m_value (value) {}
806 152 : ~ResourceHolder() { reset(); }
807 :
808 302 : T & get() { return m_value; }
809 : T const & get() const { return m_value; }
810 :
811 300 : void set (T const & value) { m_value = value; }
812 152 : void reset (T const & value = T())
813 : {
814 152 : T tmp (m_value);
815 152 : if (tmp != value)
816 0 : destructor_type()(tmp);
817 152 : set (value);
818 152 : }
819 148 : T release()
820 : {
821 148 : T tmp (m_value);
822 148 : set (T());
823 148 : return tmp;
824 : }
825 :
826 : ResourceHolder (ResourceHolder & rhs)
827 : {
828 : set (rhs.release());
829 : }
830 : ResourceHolder & operator= (ResourceHolder & rhs)
831 : {
832 : reset (rhs.release());
833 : return *this;
834 : }
835 : };
836 :
837 : storeError
838 150 : FileLockBytes_createInstance (
839 : rtl::Reference< ILockBytes > & rxLockBytes,
840 : rtl_uString * pFilename,
841 : storeAccessMode eAccessMode
842 : )
843 : {
844 : // Acquire file handle.
845 150 : ResourceHolder<FileHandle> xFile;
846 150 : storeError result = xFile.get().initialize (pFilename, eAccessMode);
847 150 : if (result != store_E_None)
848 2 : return result;
849 :
850 148 : if (eAccessMode == store_AccessReadOnly)
851 : {
852 2 : ResourceHolder<FileMapping> xMapping;
853 2 : if (xMapping.get().initialize (xFile.get().m_handle) == osl_File_E_None)
854 : {
855 0 : rxLockBytes = new MappedLockBytes (xMapping.get());
856 0 : if (!rxLockBytes.is())
857 0 : return store_E_OutOfMemory;
858 0 : (void) xFile.release();
859 0 : (void) xMapping.release();
860 2 : }
861 : }
862 148 : if (!rxLockBytes.is())
863 : {
864 148 : rxLockBytes = new FileLockBytes (xFile.get());
865 148 : if (!rxLockBytes.is())
866 0 : return store_E_OutOfMemory;
867 148 : (void) xFile.release();
868 : }
869 :
870 148 : return store_E_None;
871 : }
872 :
873 : storeError
874 2 : MemoryLockBytes_createInstance (
875 : rtl::Reference< ILockBytes > & rxLockBytes
876 : )
877 : {
878 2 : rxLockBytes = new MemoryLockBytes();
879 2 : if (!rxLockBytes.is())
880 0 : return store_E_OutOfMemory;
881 :
882 2 : return store_E_None;
883 : }
884 :
885 : } // namespace store
886 :
887 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|