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