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 */ 54 OStoreLockBytes::OStoreLockBytes (void) 55 : m_xManager (), 56 m_xNode (), 57 m_bWriteable (false) 58 { 59 } 60 61 /* 62 * ~OStoreLockBytes. 63 */ 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 */ 82 sal_Bool SAL_CALL OStoreLockBytes::isKindOf (sal_uInt32 nTypeId) 83 { 84 return (nTypeId == m_nTypeId); 85 } 86 87 /* 88 * create. 89 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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