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