1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "SyncML_DM_Archiver.H" 18 #include "SyncML_DM_WBXMLArchive.H" 19 #include "xpl_Logger.h" 20 #include "dm_tree_class.H" 21 #include "dm_uri_utils.h" 22 #include "dm_tree_plugin_util.H" //for Util function defns 23 #include "dmprofile.h" 24 #include "dmLockingHelper.h" 25 #include "dmtTreeImpl.hpp" 26 27 #ifdef TEST_DM_RECOVERY 28 char power_fail_point[20] = {0}; 29 #endif 30 31 SyncML_DM_Archiver::SyncML_DM_Archiver() 32 : m_numArchives( 0 ), 33 m_pTree( NULL ), 34 m_pEnv( NULL ) 35 { 36 // [0] is always root archive 37 38 for( int i = 0; i < MAX_ARCHIVES; ++i ) 39 { 40 m_pArchives[ i ] = NULL; 41 } 42 } 43 44 SYNCML_DM_RET_STATUS_T SyncML_DM_Archiver::initArchives( CEnv* env, DMTree* tree ) 45 { 46 SYNCML_DM_RET_STATUS_T retStat=SYNCML_DM_SUCCESS; 47 48 if( !tree || !env ) return SYNCML_DM_FAIL; 49 m_pTree = tree; 50 m_pEnv = env; 51 52 //Load All the archives 53 m_numArchives=0; 54 m_pArchives[0]=NULL; 55 56 //Load from TreeMountList and new all the Archives 57 const char *pEntryTreePath = NULL; 58 const char *pEntryURI = NULL; 59 60 INT32 i = 0; //tree mount start from 0 61 62 // Get the first mount list entry 63 m_pTree->GetTreeMountEntry(pEntryURI, pEntryTreePath, i); 64 65 while(pEntryURI != NULL && pEntryTreePath != NULL) 66 { 67 /* Create the archive if it exists in the mount list */ 68 m_pArchives[m_numArchives]=NULL; 69 70 if ( DmStrlen(pEntryTreePath) ) 71 { 72 m_pArchives[m_numArchives]=new SyncML_DM_WBXMLArchive(env, pEntryURI, pEntryTreePath); 73 74 if ( !m_pArchives[m_numArchives] ) 75 return SYNCML_DM_DEVICE_FULL; 76 77 if ( m_pArchives[m_numArchives]->Init(tree) != SYNCML_DM_SUCCESS ) 78 return SYNCML_DM_FAIL; 79 80 // XPL_LOG_DM_TMN_Debug(("pEntryURI=%s, archive=%x\n", pEntryURI, m_pArchives[m_numArchives])); 81 82 INT32 parentindex=-1; 83 INT32 parentlen=0; 84 for (INT32 j=0; j< m_numArchives; j++) 85 { 86 if ( DmStrstr(pEntryURI, m_pArchives[j]->getURI())== pEntryURI) 87 { 88 INT32 len=DmStrlen(m_pArchives[j]->getURI()); 89 90 if (parentlen < len) 91 { 92 parentlen=len; 93 parentindex=j; 94 } 95 } 96 } 97 98 if (parentindex >=0) 99 m_pArchives[m_numArchives]->setParentArchive(m_pArchives[parentindex]); 100 101 m_numArchives++; 102 //Does not support More than 32 archives... 103 if (m_numArchives >=32) 104 break; 105 } 106 107 /* In case the GetTreeMountEntry service has an error, 108 * Ensure these are sensible values going in 109 */ 110 pEntryURI = NULL; 111 pEntryTreePath = NULL; 112 m_pTree->GetTreeMountEntry(pEntryURI, pEntryTreePath, ++i); 113 } 114 115 if (m_numArchives ==0) 116 retStat=SYNCML_DM_FAIL; 117 118 XPL_LOG_DM_TMN_Debug(("m_numArchives=%d\n", m_numArchives)); 119 120 #ifdef TEST_DM_RECOVERY 121 if(XPL_DM_GetEnv(SYNCML_DM_POWER_FAIL_IJECTION) != NULL) { 122 strcpy((char *)power_fail_point, (const char *)XPL_DM_GetEnv(SYNCML_DM_POWER_FAIL_IJECTION)); 123 XPL_LOG_DM_TMN_Debug(("Power Fail Injected at: %s\n", power_fail_point)); 124 } 125 #endif 126 127 return retStat; 128 } 129 130 // A helper method for making sure that ALL archives is freed 131 SYNCML_DM_RET_STATUS_T SyncML_DM_Archiver::deinitArchives() 132 { 133 SYNCML_DM_RET_STATUS_T retStat=SYNCML_DM_SUCCESS; 134 135 //serialize if needed, Do we need to do so ? The lock manager should have already do it. 136 137 //delete the archives 138 for (int i=0; i<m_numArchives; i++) 139 { 140 if ( m_pArchives[i] !=NULL) 141 { 142 delete m_pArchives[i]; 143 m_pArchives[i]=NULL; 144 } 145 } 146 147 m_numArchives = 0; 148 m_pTree = NULL; 149 m_pEnv = NULL; 150 151 return retStat; 152 } 153 154 155 /*================================================================================================== 156 157 Function: SyncML_DM_Archiver::serialize 158 159 Description: Distributes a serialization request to the proper archive(s). A search is performed 160 for the right archive relative to the root archive. All tree data will be serialized 161 to the point possible. 162 163 Returns: SYNCML_DM_FAIL - tree or archive objects are NULL or an unspecified error occurred 164 SYNCML_DM_SUCCESS - tree was successfully serialized to proper files 165 SYNCML_DM_TREE_CORRUPT - tree storage entity was corrupt to the point where 166 serialization was partially or completely impossible 167 SYNCML_DM_IO_FAILURE - I/O failure occured while trying to write to the file handle 168 169 ==================================================================================================*/ 170 SYNCML_DM_RET_STATUS_T 171 SyncML_DM_Archiver::serialize(FILESETTYPE nFileSet, CPCHAR szURI) 172 { 173 DMGlobalLockHelper oGlobalLock; // protect serialize/recovery from multi process access 174 FILESETTYPE set=1; 175 SYNCML_DM_RET_STATUS_T retStat=SYNCML_DM_SUCCESS; 176 INT32 i=0; 177 178 if( !m_pTree ) return SYNCML_DM_FAIL; 179 180 XPL_LOG_DM_TMN_Debug(("Enter to serialize\n")); 181 182 for (i=0; i< m_numArchives && m_pArchives[i] !=NULL; i++) 183 { 184 if ( (nFileSet & set) !=0 ) { 185 if (m_pArchives[i]->isDirty()) { 186 #ifdef TEST_DM_RECOVERY 187 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "DMTR_PF1") == 0)) { 188 printf("Type Ctrl-C to simulate Power Fail ...\n"); 189 sleep(30); 190 } 191 #endif 192 XPL_LOG_DM_TMN_Debug(("m_pArchives[%d] %s is dirty, to be serialized", i, m_pArchives[i]->getURI())); 193 retStat=m_pArchives[i]->serialize(m_pTree); 194 XPL_LOG_DM_TMN_Debug(("serialize retStat = %d", retStat)); 195 if (retStat != SYNCML_DM_SUCCESS ) 196 break; 197 } 198 } 199 set = set <<1; 200 } 201 202 XPL_LOG_DM_TMN_Debug(("serialize retStat = %d", retStat)); 203 if (retStat != SYNCML_DM_SUCCESS ) 204 return retStat; 205 206 /* Begin the power loss-tolerant steps to protect against a partially written Archive file: 207 * 1. Rename the original file by adding ".bak" to the name; this indicates the .temp file 208 * was completely written 209 * 2. Rename the .temp file to the original name (i.e., without the .temp extention) 210 * 3. Delete the .bak file 211 */ 212 DMString strOrgFilePathBuffer, strTmpFilePathBuffer, strBakFilePathBuffer; 213 214 char *orgFilePath = strOrgFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 215 char *tmpFilePath =strTmpFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 216 char *bakFilePath = strBakFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 217 XPL_FS_RET_STATUS_T ret=0; 218 BOOLEAN bAtLeastOneDirty = FALSE; // check if at least one change exist to invoke commit plug-in 219 220 if ( !orgFilePath || !tmpFilePath || !bakFilePath) 221 return SYNCML_DM_DEVICE_FULL; 222 223 224 // 2nd Change File names, orig->bak 225 for (i=0, set=1; i< m_numArchives && m_pArchives[i] !=NULL; i++, set = set <<1) 226 { 227 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() && m_pArchives[i]->isWritableExist() ) 228 { 229 #ifdef TEST_DM_RECOVERY 230 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "DMTR_PF2") == 0)) { 231 printf("Type Ctrl-C to simulate Power Fail ...\n"); 232 sleep(30); 233 } 234 #endif 235 #ifdef LOB_SUPPORT 236 retStat = m_pArchives[i]->CloseCommitLog(); 237 if (retStat != SYNCML_DM_SUCCESS ) 238 return retStat; 239 #endif 240 m_pArchives[i]->getFilePath(orgFilePath, ""); 241 m_pArchives[i]->getFilePath(bakFilePath, ".bak"); 242 ret=XPL_FS_Rename( orgFilePath, bakFilePath ); 243 if (ret != XPL_FS_RET_SUCCESS) 244 { 245 ret=XPL_FS_Rename( orgFilePath, bakFilePath ); 246 retStat=SYNCML_DM_IO_FAILURE; 247 break; 248 } 249 } 250 } 251 252 for (i=0, set=1; i< m_numArchives && m_pArchives[i] !=NULL; i++, set = set <<1) 253 { 254 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() ) 255 { 256 #ifdef TEST_DM_RECOVERY 257 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "DMTR_PF3") == 0)) { 258 printf("Type Ctrl-C to simulate Power Fail ...\n"); 259 sleep(30); 260 } 261 #endif 262 263 bAtLeastOneDirty = TRUE; 264 265 m_pArchives[i]->getFilePath(tmpFilePath, ".temp"); 266 m_pArchives[i]->getFilePath(orgFilePath, ""); 267 m_pArchives[i]->getFilePath(bakFilePath, ".bak"); 268 ret=XPL_FS_Rename(tmpFilePath, orgFilePath); 269 if (ret != XPL_FS_RET_SUCCESS) 270 { 271 ret=XPL_FS_Rename(bakFilePath, orgFilePath); 272 retStat=SYNCML_DM_IO_FAILURE; 273 break; 274 } 275 } 276 } 277 278 // commit plug-in support - invoke it only when some changes were done 279 if ( bAtLeastOneDirty ) 280 InvokeCommitPlugins( nFileSet, szURI ); 281 282 for (i=0, set=1; i< m_numArchives && m_pArchives[i] !=NULL; i++, set = set <<1) 283 { 284 //set dirty to false 285 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() ) 286 { 287 #ifdef TEST_DM_RECOVERY 288 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "DMTR_PF4") == 0)) { 289 printf("Type Ctrl-C to simulate Power Fail ...\n"); 290 sleep(30); 291 } 292 #endif 293 #ifdef LOB_SUPPORT 294 // Commit changes for ESN 295 retStat=m_pArchives[i]->commitESN(m_pTree); 296 #endif 297 m_pArchives[i]->setDirty(false); 298 299 //Let each archive finished its own task, reset timestamp etc. 300 m_pArchives[i]->serializeDone(); 301 XPL_LOG_DM_TMN_Debug(("serializeDone for %s\n", orgFilePath)); 302 303 if ( m_pArchives[i]->isWritableExist() ) 304 { 305 m_pArchives[i]->getFilePath(bakFilePath, ".bak"); 306 307 #ifndef DM_NO_LOCKING 308 ret=XPL_FS_Unlink(bakFilePath); 309 #else 310 ret=XPL_FS_Remove(bakFilePath); 311 #endif 312 XPL_LOG_DM_TMN_Debug(("delete archives[%d] %s ret=%d\n", i, bakFilePath, ret)); 313 if (ret != XPL_FS_RET_SUCCESS) 314 { 315 retStat = SYNCML_DM_IO_FAILURE; 316 break; 317 } 318 } 319 } 320 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() ) 321 m_pArchives[i]->setWritableExist(TRUE); 322 323 } 324 325 return retStat; 326 } 327 328 /*================================================================================================== 329 330 Function: SyncML_DM_Archiver::deserialize 331 332 Description: Distributes a deserialization request to the proper archive(s). Each archive (starting 333 with the root archive) will deserialize into the DM T/N Manager using the AddNode 334 method for passing nodes. 335 336 Returns: SYNCML_DM_FAIL - tree or archive objects are NULL or an unspecified error occured 337 SYNCML_DM_SUCCESS - tree was successfully deserialized from proper files 338 SYNCML_DM_TREE_CORRUPT - tree storage entity was corrupt to the point where 339 deserialization was partially or completely impossible 340 SYNCML_DM_FILE_NOT_FOUND - file was unavailable for deserialization 341 SYNCML_DM_IO_FAILURE - I/O failure occured while trying to read from the file handle 342 343 ==================================================================================================*/ 344 SYNCML_DM_RET_STATUS_T 345 SyncML_DM_Archiver::deserialize(FILESETTYPE nFileSet, 346 SYNCML_DM_TREE_LOCK_TYPE_T eLockType) 347 { 348 DMGlobalLockHelper oGlobalLock; // protect serialize/recovery from multi process access 349 FILESETTYPE set=1; 350 SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS; 351 352 if( !m_pTree ) return SYNCML_DM_FAIL; 353 354 checkRecovery(); 355 356 // do not load files itself, instead create only skeleton based on file set. 357 for (INT32 i=0; i< m_numArchives && m_pArchives[i] !=NULL; i++) 358 { 359 if ( (nFileSet & set) !=0 ) 360 { 361 BOOLEAN bIsPermitted = TRUE; 362 bIsPermitted = m_pArchives[i]->verifyPermission(XPL_FS_RDONLY_MODE); 363 364 if ( bIsPermitted ) 365 { 366 367 if ( !m_pArchives[i]->LoadSkeleton(m_pTree)) 368 dm_stat = SYNCML_DM_DEVICE_FULL; 369 370 if ( dm_stat != SYNCML_DM_SUCCESS ) 371 return dm_stat; 372 373 if ( eLockType == SYNCML_DM_LOCK_TYPE_SHARED ) 374 { 375 dm_stat = m_pArchives[i]->deserialize(m_pTree,TRUE); 376 } 377 } 378 379 m_pArchives[i]->setDirty(FALSE); 380 381 } 382 set = set <<1; 383 } 384 385 XPL_LOG_DM_TMN_Debug(("End of all deserialize retStat=%d\n", dm_stat)); 386 return dm_stat; 387 } 388 389 390 //Get all required Archives containing the URI 391 FILESETTYPE SyncML_DM_Archiver::getArchivesByURI(CPCHAR pURI) const 392 { 393 FILESETTYPE nFileSet=0; 394 FILESETTYPE set=1; 395 SyncML_DM_Archive* pArchive=NULL; 396 397 INT32 containingArchive=0; 398 INT32 containingArchiveURIlen=0; 399 BOOLEAN bContainingNeeded = TRUE; 400 401 //set = set <<1; //start from 2nd file 402 for (int i=0; i< m_numArchives; i++) //NOT detect root ! 403 { 404 pArchive = m_pArchives[i]; 405 406 //For now assume no recursive files 407 const char * archivePath=pArchive->getURI(); 408 409 char * ptr=NULL; 410 411 //we need any file that is subtree of the pURI 412 //For example, archivePath=./abc pURI=. then 413 //if we found pURI under archivePath, we go 414 ptr=(char*)DmStrstr(archivePath, pURI ); 415 416 if ( ptr !=NULL && ptr == archivePath ) { 417 nFileSet= nFileSet | set; 418 } 419 420 // in case when we hit exactly root path , we don't need parent 421 if ( DmStrcmp( archivePath, pURI ) == 0 ) 422 bContainingNeeded = FALSE; 423 424 //search for longest archives that has the pURI as a childnode 425 //For example, archivePath=./abc pURI=./abc/def then 426 //if we found archivePath under pURI, we go 427 ptr=(char*)DmStrstr(pURI, archivePath ); 428 429 if (ptr !=NULL && ptr == pURI) { 430 if (containingArchiveURIlen < (INT32)DmStrlen(archivePath)) { 431 containingArchive=i; 432 containingArchiveURIlen = DmStrlen(archivePath); 433 } 434 } 435 436 set = set <<1; 437 } 438 439 if ( bContainingNeeded ) 440 nFileSet=nFileSet | (1 << (containingArchive)); //we need the containing archive 441 442 //Debug("Add file [%d] to set, %s\n", containingArchive, m_pArchives[containingArchive]); 443 444 return nFileSet; 445 } 446 447 448 449 //Get exact Archive containing the URI 450 SyncML_DM_Archive* SyncML_DM_Archiver::getArchiveByURI(CPCHAR pURI) const 451 { 452 453 454 FILESETTYPE nFileSet ; 455 FILESETTYPE set=1; 456 INT32 index = 0; 457 458 nFileSet = getArchivesByURI(pURI); 459 460 for (INT32 i=0; i< m_numArchives && m_pArchives[i] !=NULL; i++) 461 { 462 if ( (nFileSet & set) !=0 ) 463 { 464 if ( DmIsParentURI(m_pArchives[i]->getURI(), pURI) ) 465 { 466 index = i; 467 break; 468 } 469 } 470 set = set <<1; 471 } 472 473 //XPL_LOG_DM_TMN_Debug(("returning archive=%x, uri=%s\n",m_pArchives[index], pURI )); 474 return m_pArchives[index]; 475 } 476 477 /*================================================================================================== 478 479 Function: SyncML_DM_Archiver::checkRecovery 480 481 Description: Resolve recovery records after a serious phone critical failure event 482 483 Returns: SYNCML_DM_SUCCESS 484 SYNCML_DM_IO_FAILURE 485 SYNCML_DM_FILE_NOT_FOUND 486 SYNCML_DM_LOG_CORRUPT 487 488 ==================================================================================================*/ 489 SYNCML_DM_RET_STATUS_T 490 SyncML_DM_Archiver::checkRecovery() 491 { 492 if( !m_pTree ) return SYNCML_DM_FAIL; 493 494 SYNCML_DM_RET_STATUS_T retStat=SYNCML_DM_SUCCESS; 495 496 //Check and recover All nodes all at once. 497 DMString strOrgFilePathBuffer, strTmpFilePathBuffer, strBakFilePathBuffer, strCmtFilePathBuffer; 498 499 char *orgFilePath = strOrgFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 500 char *tmpFilePath =strTmpFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 501 char *bakFilePath = strBakFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 502 char *cmtFilePath = strCmtFilePathBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH); 503 504 if ( !orgFilePath || !tmpFilePath || !bakFilePath || !cmtFilePath) 505 return SYNCML_DM_DEVICE_FULL; 506 507 XPL_FS_RET_STATUS_T ret=0; 508 509 //Logic for checking corrupted files 510 BOOLEAN tmpFileExists=FALSE; 511 BOOLEAN bakFileExists=FALSE; 512 BOOLEAN cmtFileExists=FALSE; 513 INT32 i; 514 515 if ( DmGetMemFailedFlag() ) // device runs out of memory 516 return SYNCML_DM_DEVICE_FULL; 517 518 m_pTree->RecoverPlugin(); 519 520 for (i=0; i< m_numArchives; i++) 521 { 522 m_pArchives[i]->getFilePath(orgFilePath, ""); 523 m_pArchives[i]->getFilePath(bakFilePath, ".bak"); 524 m_pArchives[i]->getFilePath(tmpFilePath, ".temp"); 525 m_pArchives[i]->getFilePath(cmtFilePath, ".cmt"); 526 527 if (XPL_FS_Exist(tmpFilePath)) 528 tmpFileExists=TRUE; 529 if (XPL_FS_Exist(bakFilePath)) 530 bakFileExists=TRUE; 531 if (XPL_FS_Exist(cmtFilePath)) 532 cmtFileExists=TRUE; 533 } 534 535 if ( tmpFileExists || bakFileExists ) 536 XPL_FS_Remove(DM_ISP_LOCK); 537 538 if (tmpFileExists) 539 { 540 if (bakFileExists) 541 { 542 //Both temp file and bak file exists, rename bak to orig 543 // rename bak files to orig files, then delete tmp files and commit log files 544 for (i=0; i< m_numArchives; i++) 545 { 546 m_pArchives[i]->getFilePath(orgFilePath, ""); 547 m_pArchives[i]->getFilePath(bakFilePath, ".bak"); 548 ret=XPL_FS_Rename(bakFilePath, orgFilePath); 549 XPL_LOG_DM_TMN_Debug(("DmFsRename %s->%s ret=%d\n", bakFilePath, orgFilePath, ret)); 550 } 551 } 552 for (i=0; i< m_numArchives; i++) 553 { 554 m_pArchives[i]->getFilePath(tmpFilePath, ".temp"); 555 m_pArchives[i]->getFilePath(cmtFilePath, ".cmt"); 556 #ifndef DM_NO_LOCKING 557 ret=XPL_FS_Unlink(tmpFilePath); 558 ret=XPL_FS_Unlink(cmtFilePath); 559 #else 560 ret=XPL_FS_Remove(tmpFilePath); 561 ret=XPL_FS_Remove(cmtFilePath); 562 #endif 563 XPL_LOG_DM_TMN_Debug(("delete %s ret=%d\n", tmpFilePath, ret)); 564 } 565 } 566 else 567 { 568 if (bakFileExists | cmtFileExists) 569 { 570 //Only bak file exists 571 // Delete bak files 572 for (i=0; i< m_numArchives; i++) 573 { 574 m_pArchives[i]->getFilePath(bakFilePath, ".bak"); 575 m_pArchives[i]->getFilePath(cmtFilePath, ".cmt"); 576 // Remove .bak file 577 if (XPL_FS_Exist(bakFilePath)) 578 { 579 #ifndef DM_NO_LOCKING 580 ret=XPL_FS_Unlink(bakFilePath); 581 #else 582 ret=XPL_FS_Remove(bakFilePath); 583 #endif 584 XPL_LOG_DM_TMN_Debug(("delete %s ret=%d\n", bakFilePath, ret)); 585 } 586 #ifdef LOB_SUPPORT 587 // Play and remove commit log file 588 if (XPL_FS_Exist(cmtFilePath)) 589 { 590 m_pArchives[i]->PlayCommitLog(); 591 } 592 #endif 593 } 594 } 595 } 596 597 // Remove temorary LOB files 598 { 599 DMString lobDir; 600 m_pEnv->GetWFSFullPath(NULL,lobDir); 601 DmRemoveTempfile(lobDir); 602 } 603 604 //Logic for checking newer files 605 for (i=0; i< m_numArchives && m_pArchives[i] !=NULL; i++) 606 { 607 if (m_pArchives[i]->getRootNode() !=NULL && !m_pArchives[i]->getRootNode()->IsSkeletonNode()) 608 { 609 //Already loaded in memory 610 if (m_pArchives[i]->getLastModifiedTime() != m_pArchives[i]->getLastSavedTime()) 611 { 612 //The files needed to be reloaded. 613 XPL_LOG_DM_TMN_Debug(("File[%d] %s is newer, need delete subtree & reload\n", i, m_pArchives[i]->getURI())); 614 XPL_LOG_DM_TMN_Debug((" last file modified time=0x%x memory time=0x%x\n",m_pArchives[i]->getLastModifiedTime(), m_pArchives[i]->getLastSavedTime())); 615 m_pTree->UnloadArchive(m_pArchives[i]->getRootNode()); 616 } 617 } 618 } 619 620 return retStat; 621 } 622 623 SYNCML_DM_RET_STATUS_T 624 SyncML_DM_Archiver::rollback(INT32 nFileSet) 625 { 626 if( !m_pTree ) return SYNCML_DM_FAIL; 627 628 SYNCML_DM_RET_STATUS_T retStat=SYNCML_DM_SUCCESS; 629 630 INT32 i=0; 631 INT32 set=1; 632 for (i=0, set=1; i< m_numArchives && m_pArchives[i] !=NULL; i++, set = set <<1 ) 633 { 634 if ( (nFileSet & set) !=0 && m_pArchives[i]->getRootNode() != NULL ) 635 { 636 //Already loaded in memory 637 if ( m_pArchives[i]->isDirty() ) 638 { 639 //The files needed to be reloaded. 640 XPL_LOG_DM_TMN_Debug((" last file modified time=0x%x memory time=0x%x\n", m_pArchives[i]->getLastModifiedTime(), 641 m_pArchives[i]->getLastSavedTime())); 642 643 #ifdef LOB_SUPPORT 644 // Rollback all changes for ESN 645 m_pArchives[i]->rollbackESN(m_pTree); 646 #endif 647 m_pTree->UnloadArchive(m_pArchives[i]->getRootNode()); 648 m_pArchives[i]->setDirty(FALSE); 649 m_pArchives[i]->GetEventLogger().Reset(); 650 } 651 } 652 } 653 654 return retStat; 655 } 656 657 void 658 SyncML_DM_Archiver::CheckMemoryAging(INT32 nAgingTime) 659 { 660 if( !m_pTree ) return; 661 662 // current time in seconds 663 XPL_CLK_CLOCK_T currentTime = XPL_CLK_GetClock(); 664 for (INT32 i=0; i < m_numArchives && m_pArchives[i] !=NULL; i++) 665 { 666 // free from memory 667 if ( m_pArchives[i]->getRootNode() 668 && !m_pArchives[i]->getRootNode()->IsSkeletonNode() 669 && !m_pArchives[i]->isDirty() ) 670 { 671 // Check the last accessed time in seconds 672 XPL_CLK_CLOCK_T lastAccessedTime = m_pArchives[i]->getLastAccessedTime(); 673 if ( (currentTime - lastAccessedTime) >= (XPL_CLK_CLOCK_T)nAgingTime ) 674 { 675 XPL_LOG_DM_TMN_Debug(("m_pArchives[%d]->getURI() : %s is being unloaded, unused for %d >= aging time = %d\n", 676 i, m_pArchives[i]->getURI(), (currentTime - lastAccessedTime), nAgingTime)); 677 } 678 679 m_pTree->UnloadArchive(m_pArchives[i]->getRootNode()); 680 } 681 } 682 } 683 684 //------------------------------------------------------------------------ 685 // FUNCTION : InvokeCommitPlugins 686 // DESCRIPTION : This function iterates all commit plug-ins 687 // and calls "OnCommit" on each which has update event(s) 688 // ARGUMENTS PASSED: szURI - sub-tree root uri 689 // nFileSet - currently used file set 690 // RETURN VALUE : void 691 // PRE-CONDITIONS : called after successful serialization 692 // POST-CONDITIONS : 693 // IMPORTANT NOTES : 694 // REQUIREMENT # : 695 //------------------------------------------------------------------------ 696 void SyncML_DM_Archiver::InvokeCommitPlugins(FILESETTYPE nFileSet, CPCHAR szURI) 697 { 698 PDmtTree tree( new DmtTreeImpl(true) ); 699 DMPluginVector plugins; 700 FILESETTYPE set=1; 701 INT32 i=0; 702 703 DMPluginManager & oPluginManager = m_pTree->GetPluginManager(); 704 705 oPluginManager.GetPlugins(szURI, SYNCML_DM_COMMIT_PLUGIN, plugins); 706 707 for (INT32 nPlugin = 0; nPlugin < plugins.size(); nPlugin++ ) 708 { 709 DmtEventMap updatedNodes; 710 711 for (i=0, set=1; i< m_numArchives && m_pArchives[i] !=NULL; i++, set = set <<1) 712 { 713 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() ) 714 { 715 m_pArchives[i]->GetEventLogger().GetCommitPluginEvents(plugins[nPlugin], updatedNodes ); 716 } 717 } 718 719 if ( updatedNodes.size() > 0 ) 720 plugins[nPlugin]->OnCommit( updatedNodes, tree ); 721 } 722 } 723 724 725 //------------------------------------------------------------------------ 726 // FUNCTION : CleanEvents 727 // DESCRIPTION : This function iterates all archives and remove stored events 728 // ARGUMENTS PASSED: szURI - sub-tree root uri 729 // RETURN VALUE : void 730 // PRE-CONDITIONS : called after successful serialization 731 // POST-CONDITIONS : 732 // IMPORTANT NOTES : 733 // REQUIREMENT # : 734 //------------------------------------------------------------------------ 735 SYNCML_DM_RET_STATUS_T 736 SyncML_DM_Archiver::CleanEvents(CPCHAR szURI) 737 738 { 739 FILESETTYPE set=1; 740 FILESETTYPE nFileSet=0; 741 742 nFileSet = getArchivesByURI(szURI); 743 744 for (FILESETTYPE i=0, set=1; i < m_numArchives; i++, set <<= 1) 745 { 746 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() ) 747 { 748 m_pArchives[i]->GetEventLogger().CleanEvents(szURI); 749 } 750 } 751 return SYNCML_DM_SUCCESS; 752 } 753 754 755 //------------------------------------------------------------------------ 756 // FUNCTION : UpdateEvents 757 // DESCRIPTION : This function iterates all archives and remove stored events 758 // ARGUMENTS PASSED: szURI - sub-tree root uri 759 // RETURN VALUE : void 760 // PRE-CONDITIONS : called after successful serialization 761 // POST-CONDITIONS : 762 // IMPORTANT NOTES : 763 // REQUIREMENT # : 764 //------------------------------------------------------------------------ 765 SYNCML_DM_RET_STATUS_T 766 SyncML_DM_Archiver::UpdateEvents(CPCHAR szURI, CPCHAR szNewName) 767 768 { 769 FILESETTYPE set=1; 770 FILESETTYPE nFileSet=0; 771 772 nFileSet = getArchivesByURI(szURI); 773 774 for (FILESETTYPE i=0, set=1; i< m_numArchives; i++, set = set <<1) 775 { 776 if ( (nFileSet & set) !=0 && m_pArchives[i]->isDirty() ) 777 { 778 m_pArchives[i]->GetEventLogger().UpdateEvents(szURI,szNewName); 779 } 780 } 781 return SYNCML_DM_SUCCESS; 782 } 783 784 //------------------------------------------------------------------------ 785 // FUNCTION : IsDirty 786 // DESCRIPTION : Checks if file set has been modified 787 // 788 // ARGUMENTS PASSED: nFileSet - currently used file set 789 // RETURN VALUE : void 790 // PRE-CONDITIONS : called before serialization 791 // POST-CONDITIONS : 792 // IMPORTANT NOTES : 793 // REQUIREMENT # : 794 //------------------------------------------------------------------------ 795 BOOLEAN SyncML_DM_Archiver::IsDirty(FILESETTYPE * pFileSet) 796 { 797 FILESETTYPE i=0; 798 FILESETTYPE set=1; 799 800 if ( pFileSet == NULL ) 801 return TRUE; 802 803 for (i=0, set=1; i< m_numArchives; i++, set = set <<1) 804 { 805 if ( ((*pFileSet) & set) !=0 && m_pArchives[i]->isDirty() == FALSE ) 806 (*pFileSet) &= ~set; 807 } 808 809 if ( (*pFileSet) == 0 ) 810 return FALSE; 811 else 812 return TRUE; 813 } 814