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