xref: /trunk/main/store/source/storlckb.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 "storlckb.hxx"
28 
29 #include "sal/types.h"
30 #include "sal/macros.h"
31 #include "rtl/string.h"
32 #include "rtl/ref.hxx"
33 #include "osl/mutex.hxx"
34 
35 #include "store/types.h"
36 #include "object.hxx"
37 
38 #include "storbase.hxx"
39 #include "stordata.hxx"
40 #include "storpage.hxx"
41 
42 using namespace store;
43 
44 /*========================================================================
45  *
46  * OStoreLockBytes implementation.
47  *
48  *======================================================================*/
49 const sal_uInt32 OStoreLockBytes::m_nTypeId = sal_uInt32(0x94190310);
50 
51 /*
52  * OStoreLockBytes.
53  */
OStoreLockBytes(void)54 OStoreLockBytes::OStoreLockBytes (void)
55 	: m_xManager   (),
56 	  m_xNode      (),
57 	  m_bWriteable (false)
58 {
59 }
60 
61 /*
62  * ~OStoreLockBytes.
63  */
~OStoreLockBytes(void)64 OStoreLockBytes::~OStoreLockBytes (void)
65 {
66 	if (m_xManager.is())
67 	{
68 		if (m_xNode.is())
69 		{
70 			OStorePageDescriptor aDescr (m_xNode->m_aDescr);
71 			if (m_bWriteable)
72                 m_xManager->releasePage (aDescr, store_AccessReadWrite);
73 			else
74                 m_xManager->releasePage (aDescr, store_AccessReadOnly);
75 		}
76 	}
77 }
78 
79 /*
80  * isKindOf.
81  */
isKindOf(sal_uInt32 nTypeId)82 sal_Bool SAL_CALL OStoreLockBytes::isKindOf (sal_uInt32 nTypeId)
83 {
84 	return (nTypeId == m_nTypeId);
85 }
86 
87 /*
88  * create.
89  */
create(OStorePageManager * pManager,rtl_String * pPath,rtl_String * pName,storeAccessMode eMode)90 storeError OStoreLockBytes::create (
91 	OStorePageManager *pManager,
92 	rtl_String        *pPath,
93 	rtl_String        *pName,
94 	storeAccessMode    eMode)
95 {
96 	rtl::Reference<OStorePageManager> xManager (pManager);
97 	if (!xManager.is())
98 		return store_E_InvalidAccess;
99 
100 	if (!(pPath && pName))
101 		return store_E_InvalidParameter;
102 
103 	OStoreDirectoryPageObject aPage;
104 	storeError eErrCode = xManager->iget (
105 		aPage, STORE_ATTRIB_ISFILE,
106 		pPath, pName, eMode);
107 	if (eErrCode != store_E_None)
108 		return eErrCode;
109 
110 	if (!(aPage.attrib() & STORE_ATTRIB_ISFILE))
111 	{
112 		// No ISFILE in older versions (backward compatibility).
113 		if (aPage.attrib() & STORE_ATTRIB_ISLINK)
114 			return store_E_NotFile;
115 	}
116 
117 	// ...
118     inode_holder_type xNode (aPage.get());
119 	if (eMode != store_AccessReadOnly)
120 		eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadWrite);
121 	else
122 		eErrCode = xManager->acquirePage (xNode->m_aDescr, store_AccessReadOnly);
123 	if (eErrCode != store_E_None)
124 		return eErrCode;
125 
126 	// ...
127 	m_xManager   = xManager;
128 	m_xNode      = xNode;
129 	m_bWriteable = (eMode != store_AccessReadOnly);
130 
131 	// Check for truncation.
132 	if (eMode == store_AccessCreate)
133 	{
134 		// Truncate to zero length.
135 		eErrCode = setSize(0);
136 	}
137 	return eErrCode;
138 }
139 
140 /*
141  * readAt.
142  */
readAt(sal_uInt32 nOffset,void * pBuffer,sal_uInt32 nBytes,sal_uInt32 & rnDone)143 storeError OStoreLockBytes::readAt (
144 	sal_uInt32  nOffset,
145 	void       *pBuffer,
146 	sal_uInt32  nBytes,
147 	sal_uInt32 &rnDone)
148 {
149 	rnDone = 0;
150 
151 	if (!m_xManager.is())
152 		return store_E_InvalidAccess;
153 
154 	if (!pBuffer)
155 		return store_E_InvalidParameter;
156 	if (!nBytes)
157 		return store_E_None;
158 
159 	// Acquire exclusive access.
160 	osl::MutexGuard aGuard (*m_xManager);
161 
162 	// Determine data length.
163 	OStoreDirectoryPageObject aPage (m_xNode.get());
164 
165 	sal_uInt32 nDataLen = aPage.dataLength();
166 	if ((nOffset + nBytes) > nDataLen)
167 		nBytes = nDataLen - nOffset;
168 
169 	// Read data.
170     OStoreDataPageObject aData;
171 	sal_uInt8 *pData = (sal_uInt8*)pBuffer;
172 	while ((0 < nBytes) && (nOffset < nDataLen))
173 	{
174 		// Determine 'Offset' scope.
175 		inode::ChunkScope eScope = m_xNode->scope (nOffset);
176 		if (eScope == inode::SCOPE_INTERNAL)
177 		{
178 			// Read from inode page (internal scope).
179 			inode::ChunkDescriptor aDescr (
180 				nOffset, m_xNode->capacity());
181 
182 			sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
183 			nLength = SAL_MIN(nLength, nBytes);
184 
185 			memcpy (
186 				&pData[rnDone],
187 				&m_xNode->m_pData[aDescr.m_nOffset],
188 				nLength);
189 
190 			// Adjust counters.
191 			rnDone  += nLength;
192 			nOffset += nLength;
193 			nBytes  -= nLength;
194 		}
195 		else
196 		{
197 			// Read from data page (external scope).
198 			inode::ChunkDescriptor aDescr (
199 				nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@
200 
201 			sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
202 			nLength = SAL_MIN(nLength, nBytes);
203 
204 			storeError eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager);
205 			if (eErrCode != store_E_None)
206 			{
207 				if (eErrCode != store_E_NotExists)
208 					return eErrCode;
209 
210 				memset (
211 					&pData[rnDone],
212                     0,
213 					nLength);
214 			}
215 			else
216 			{
217                 PageHolderObject< data > xData (aData.makeHolder<data>());
218 				memcpy (
219 					&pData[rnDone],
220 					&xData->m_pData[aDescr.m_nOffset],
221 					nLength);
222 			}
223 
224 			// Adjust counters.
225 			rnDone  += nLength;
226 			nOffset += nLength;
227 			nBytes  -= nLength;
228 		}
229 	}
230 
231 	// Done.
232 	return store_E_None;
233 }
234 
235 /*
236  * writeAt.
237  */
writeAt(sal_uInt32 nOffset,const void * pBuffer,sal_uInt32 nBytes,sal_uInt32 & rnDone)238 storeError OStoreLockBytes::writeAt (
239 	sal_uInt32  nOffset,
240 	const void *pBuffer,
241 	sal_uInt32  nBytes,
242 	sal_uInt32 &rnDone)
243 {
244 	rnDone = 0;
245 
246 	if (!m_xManager.is())
247 		return store_E_InvalidAccess;
248 	if (!m_bWriteable)
249 		return store_E_AccessViolation;
250 
251 	if (!pBuffer)
252 		return store_E_InvalidParameter;
253 	if (!nBytes)
254 		return store_E_None;
255 
256 	// Acquire exclusive access.
257 	osl::MutexGuard aGuard (*m_xManager);
258 
259 	// Write data.
260 	OStoreDirectoryPageObject aPage (m_xNode.get());
261 	const sal_uInt8 *pData = (const sal_uInt8*)pBuffer;
262 
263 	storeError eErrCode = store_E_None;
264 	while (nBytes > 0)
265 	{
266 		// Determine 'Offset' scope.
267 		inode::ChunkScope eScope = m_xNode->scope (nOffset);
268 		if (eScope == inode::SCOPE_INTERNAL)
269 		{
270 			// Write to inode page (internal scope).
271 			inode::ChunkDescriptor aDescr (
272 				nOffset, m_xNode->capacity());
273 
274 			sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
275 			nLength = SAL_MIN(nLength, nBytes);
276 
277 			memcpy (
278 				&m_xNode->m_pData[aDescr.m_nOffset],
279 				&pData[rnDone], nLength);
280 
281 			// Mark inode dirty.
282 			aPage.touch();
283 
284 			// Adjust counters.
285 			rnDone  += nLength;
286 			nOffset += nLength;
287 			nBytes  -= nLength;
288 
289 			// Adjust data length.
290 			if (aPage.dataLength() < nOffset)
291 				aPage.dataLength (nOffset);
292 		}
293 		else
294 		{
295 			// Write to data page (external scope).
296 			OStoreDataPageObject aData;
297 
298 			inode::ChunkDescriptor aDescr (
299 				nOffset - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@
300 
301 			sal_uInt32 nLength = sal_uInt32(aDescr.m_nLength);
302 			if ((aDescr.m_nOffset > 0) || (nBytes < nLength))
303 			{
304 				// Unaligned. Need to load/create data page.
305 // @@@ loadOrCreate()
306 				eErrCode = aPage.read (aDescr.m_nPage, aData, *m_xManager);
307 				if (eErrCode != store_E_None)
308 				{
309 					if (eErrCode != store_E_NotExists)
310 						return eErrCode;
311 
312                     eErrCode = aData.construct<data>(m_xManager->allocator());
313                     if (eErrCode != store_E_None)
314 						return eErrCode;
315 				}
316 			}
317 
318             PageHolderObject< data > xData (aData.makeHolder<data>());
319             if (!xData.is())
320             {
321                 eErrCode = aData.construct<data>(m_xManager->allocator());
322                 if (eErrCode != store_E_None)
323                     return eErrCode;
324                 xData = aData.makeHolder<data>();
325             }
326 
327 			// Modify data page.
328 			nLength = SAL_MIN(nLength, nBytes);
329 			memcpy (
330 				&xData->m_pData[aDescr.m_nOffset],
331 				&pData[rnDone], nLength);
332 
333 			// Save data page.
334 			eErrCode = aPage.write (aDescr.m_nPage, aData, *m_xManager);
335 			if (eErrCode != store_E_None)
336 				return eErrCode;
337 
338 			// Adjust counters.
339 			rnDone  += nLength;
340 			nOffset += nLength;
341 			nBytes  -= nLength;
342 
343 			// Adjust data length.
344 			if (aPage.dataLength() < nOffset)
345 				aPage.dataLength (nOffset);
346 		}
347 	}
348 
349 	// Check for modified inode.
350 	if (aPage.dirty())
351 		return m_xManager->saveObjectAt (aPage, aPage.location());
352 	else
353 		return store_E_None;
354 }
355 
356 /*
357  * flush.
358  */
flush(void)359 storeError OStoreLockBytes::flush (void)
360 {
361 	if (!m_xManager.is())
362 		return store_E_InvalidAccess;
363 
364 	return m_xManager->flush();
365 }
366 
367 /*
368  * setSize.
369  */
setSize(sal_uInt32 nSize)370 storeError OStoreLockBytes::setSize (sal_uInt32 nSize)
371 {
372 	if (!m_xManager.is())
373 		return store_E_InvalidAccess;
374 	if (!m_bWriteable)
375 		return store_E_AccessViolation;
376 
377 	// Acquire exclusive access.
378 	osl::MutexGuard aGuard (*m_xManager);
379 
380 	// Determine current length.
381 	OStoreDirectoryPageObject aPage (m_xNode.get());
382 	sal_uInt32 nDataLen = aPage.dataLength();
383 
384 	if (nSize == nDataLen)
385 		return store_E_None;
386 
387 	if (nSize < nDataLen)
388 	{
389 		// Truncate.
390 		storeError eErrCode = store_E_None;
391 
392 		// Determine 'Size' scope.
393 		inode::ChunkScope eSizeScope = m_xNode->scope (nSize);
394 		if (eSizeScope == inode::SCOPE_INTERNAL)
395 		{
396 			// Internal 'Size' scope. Determine 'Data' scope.
397 			inode::ChunkScope eDataScope = m_xNode->scope (nDataLen);
398 			if (eDataScope == inode::SCOPE_EXTERNAL)
399 			{
400 				// External 'Data' scope. Truncate all external data pages.
401 				eErrCode = aPage.truncate (0, *m_xManager);
402 				if (eErrCode != store_E_None)
403 					return eErrCode;
404 			}
405 
406 			// Truncate internal data page.
407 			inode::ChunkDescriptor aDescr (nSize, m_xNode->capacity());
408 			memset (
409 				&(m_xNode->m_pData[aDescr.m_nOffset]),
410 				0, aDescr.m_nLength);
411 		}
412 		else
413 		{
414 			// External 'Size' scope. Truncate external data pages.
415 			inode::ChunkDescriptor aDescr (
416 				nSize - m_xNode->capacity(), OStoreDataPageData::capacity(m_xNode->m_aDescr)); // @@@
417 
418 			sal_uInt32 nPage = aDescr.m_nPage;
419 			if (aDescr.m_nOffset) nPage += 1;
420 
421 			eErrCode = aPage.truncate (nPage, *m_xManager);
422 			if (eErrCode != store_E_None)
423 				return eErrCode;
424 		}
425 	}
426 
427 	// Set (extended or truncated) size.
428 	aPage.dataLength (nSize);
429 
430 	// Save modified inode.
431 	return m_xManager->saveObjectAt (aPage, aPage.location());
432 }
433 
434 /*
435  * stat.
436  */
stat(sal_uInt32 & rnSize)437 storeError OStoreLockBytes::stat (sal_uInt32 &rnSize)
438 {
439 	rnSize = 0;
440 
441 	if (!m_xManager.is())
442 		return store_E_InvalidAccess;
443 
444 	OStoreDirectoryPageObject aPage (m_xNode.get());
445 	rnSize = aPage.dataLength();
446 	return store_E_None;
447 }
448