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