xref: /trunk/main/store/source/lockbyte.cxx (revision 73d9b18a)
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