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