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_WBXMLArchive.H" 18 #include "SyncML_DM_Reader.H" 19 #include "xpl_Logger.h" 20 #include "dm_tree_class.H" 21 #include "dmprofile.h" 22 #include "dm_uri_utils.h" 23 24 /* The DEFAULT_FILE_HEADER field represents the start of a standard WBXML document 25 * for standards compliance and for the purpose of file size efficiency. 26 * 27 * The first 3 bytes are WBXML standard values: 28 * version is always 1 byte. 29 * publicid - We assume the public ID is <=127, which only takes 1 byte 30 * for its mb_uint32 encoding. 31 * charset - 0x6A is the code for UTF-8; 1 byte for mb_uint32 encoding 32 * The 4th byte is the mb_uint32 length of the optional string table that follows; 33 * we will not have a string table, so the length is zero and no table follows. 34 * 35 * The purpose of the string table is to store common strings that occur multiple 36 * times in the document, and thus save space by referring to them. This is a 37 * possible future enhancement. 38 */ 39 const UINT8 SyncML_DM_WBXMLArchive::DEFAULT_FILE_HEADER[] = { 40 WBXML_VERSION, PUBLIC_ID, CHARSET, 0x00 41 }; 42 43 /* The wchar_t standard and handy L"string"; usage are not supported by the ARM compiler.*/ 44 const char SyncML_DM_WBXMLArchive::FILE_EXTENSION[] = ".wbxml"; 45 46 /*================================================================================================== 47 48 Function: SyncML_DM_WBXMLArchive::SyncML_DM_WBXMLArchive 49 50 Description: Constructor method that creates a log and sets up the path and uri of the archive 51 52 ==================================================================================================*/ 53 SyncML_DM_WBXMLArchive::SyncML_DM_WBXMLArchive(CEnv* env, CPCHAR pURI, CPCHAR path) 54 : SyncML_DM_Archive( env, pURI, path), 55 m_pEnv( env ) 56 { 57 lastSavedTime = 0; 58 #ifdef LOB_SUPPORT 59 commitLog = NULL; 60 #endif 61 62 if (!m_strWFSFileName.empty() && m_strWFSFileName.length() > 0) { 63 m_permission = 0; 64 // initialize permission mask 65 if (XPL_FS_CheckPermission(m_strWFSFileName, XPL_FS_RDONLY_MODE)) { 66 m_permission = XPL_FS_RDONLY_MODE; 67 } 68 if (XPL_FS_CheckPermission(m_strWFSFileName, XPL_FS_RDWR_MODE)) { 69 m_permission |= (XPL_FS_RDWR_MODE|XPL_FS_WRONLY_MODE|XPL_FS_RDWR_MODE| 70 XPL_FS_CREAT_MODE|XPL_FS_TRUNC_MODE|XPL_FS_APPEND_MODE); 71 } 72 } 73 XPL_LOG_DM_TMN_Debug(("m_permission initialized to %d, path %s, uri=%s\n", m_permission, m_strWFSFileName.c_str(), pURI )); 74 } 75 76 /*================================================================================================== 77 78 Function: SyncML_DM_WBXMLArchive::~SyncML_DM_WBXMLArchive 79 80 Description: The SyncML_DM_WBXMLArchive class deconstructor. 81 82 ==================================================================================================*/ 83 SyncML_DM_WBXMLArchive::~SyncML_DM_WBXMLArchive() 84 { 85 #ifdef LOB_SUPPORT 86 // Remove commit log handler 87 if(commitLog != NULL) 88 { 89 commitLog->CloseLog(); 90 delete commitLog; 91 commitLog = NULL; 92 } 93 #endif 94 } 95 96 /*================================================================================================== 97 98 Function: SyncML_DM_WBXMLArchive::serialize 99 100 Description: Serialization method takes a tree as an argument serializes to the file system 101 102 ==================================================================================================*/ 103 SYNCML_DM_RET_STATUS_T 104 SyncML_DM_WBXMLArchive::serialize(DMTree* tree) 105 { 106 SYNCML_DM_SERIALIZATION_STATUS_T ser_ret_stat; 107 108 #ifdef DM_PROFILER_ENABLED 109 DMString strCaption = "serialize "; 110 strCaption += getURI(); strCaption += ", \""; 111 strCaption += m_path; strCaption += "\""; 112 DM_PROFILE( strCaption ); 113 #endif 114 115 /* Create the path string for the temp file */ 116 if (this->rootTreeNode==NULL) 117 return SYNCML_DM_SKIP_SUBTREE; 118 119 tree->InitSerializationList(this->rootTreeNode); 120 121 /* Path + Extension + null */ 122 DMString strTempFilePath = m_strWFSFileName; 123 strTempFilePath += DMFileHandler::TEMP_FILE_EXTENSION; 124 125 /* Acquire a handle representation of the file */ 126 DMFileHandler fileHandle(strTempFilePath.c_str()); 127 128 /* Open the file for writing */ 129 130 SYNCML_DM_RET_STATUS_T retstat = fileHandle.open(XPL_FS_FILE_WRITE); 131 132 if(retstat == SYNCML_DM_COMMAND_NOT_ALLOWED) { 133 return retstat; 134 } 135 else if (retstat != SYNCML_DM_SUCCESS) { 136 return SYNCML_DM_IO_FAILURE; 137 } 138 139 /* Create a WBXMLWriter utility class for handling the data */ 140 SyncML_DM_WBXMLWriter writer(&fileHandle); 141 142 /* Write the default file header, which contains the WBXML version, public ID, 143 charset (UTF-8), lookup table length, and lookup table */ 144 if(writer.writeData((UINT8 *)DEFAULT_FILE_HEADER, 145 (UINT8)sizeof(DEFAULT_FILE_HEADER)) != SYNCML_DM_SUCCESS) { 146 return SYNCML_DM_IO_FAILURE; 147 } 148 149 /* Write the MgmtTree start tag */ 150 if(writer.writeByte(SyncML_DM_WBXMLArchive::TREE_START_TAG | 151 SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK) != SYNCML_DM_SUCCESS) { 152 return SYNCML_DM_IO_FAILURE; 153 } 154 155 /* Create a URI object for the currURI 156 * For the purposes of conserving memory allocation cycles, we assume the worst 157 * case URI length + 1 for the nil terminator, and we will reuse this same 158 * buffer as the loop runs, putting in a nil terminator where its needed. 159 */ 160 DMNode * pRetNode = NULL; 161 /* Loop on the nodes returned by the tree and node manager */ 162 INT32 nEndTagsNumber = 0; 163 while((ser_ret_stat = tree->GetSerializationListNextItem(&pRetNode, nEndTagsNumber)) == SYNCML_DM_SERIALIZATION_SUCCESS) 164 { 165 166 // write "end" tags 167 while( nEndTagsNumber > 0 ) { 168 nEndTagsNumber--; 169 170 if(writer.writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS) 171 return SYNCML_DM_IO_FAILURE; 172 } 173 #ifdef LOB_SUPPORT 174 // Special case for ESN 175 if(pRetNode->IsESN()) 176 { 177 SYNCML_DM_RET_STATUS_T retStatus; 178 // Convert to ESN pointer 179 DMDefaultESN *tempESN = reinterpret_cast< DMDefaultESN *>(pRetNode); 180 // Close internal files 181 retStatus = tempESN->CloseInternalFile(); 182 if(retStatus != SYNCML_DM_SUCCESS) 183 return retStatus; 184 } 185 #endif 186 187 if(writer.writeNode(pRetNode) != SYNCML_DM_SUCCESS) { 188 XPL_LOG_DM_TMN_Error((" SYNCML_DM_IO_FAILURE on %s\n", (const char *)m_pURI )); 189 return SYNCML_DM_IO_FAILURE; 190 } 191 192 if ( pRetNode->opiInSync() ) 193 { 194 UINT8 flag = pRetNode->getFlags(); 195 flag &= ~( DMNode::enum_NodeOPISyncUptodate ); 196 pRetNode->setFlags(flag); 197 } 198 199 }/* End while */ 200 201 /* Ensure the while() terminated as expected */ 202 if (ser_ret_stat == SYNCML_DM_TREE_TRAVERSING_OVER) { 203 /* We have to write the end tag of the last node, as well as any 204 * parent nodes that also ended. currURI tells up how many (one 205 * for each / still in it) 206 */ 207 while( nEndTagsNumber > 0 ) { 208 nEndTagsNumber--; 209 210 if(writer.writeByte(SyncML_DM_WBXMLArchive::END_TAG) != SYNCML_DM_SUCCESS) 211 return SYNCML_DM_IO_FAILURE; 212 } 213 } else /* ser_ret_stat == SYNCML_DM_SERIALIZATION_FAIL */ 214 { 215 fileHandle.close(); 216 return SYNCML_DM_FAIL; 217 } 218 /* Write the end tag for the root node, then end tag for the MgmtTree */ 219 UINT8 endTags[2] = { SyncML_DM_WBXMLArchive::END_TAG, SyncML_DM_WBXMLArchive::END_TAG }; 220 221 if(writer.writeData(&endTags[0], 2) != SYNCML_DM_SUCCESS) 222 { 223 fileHandle.close(); 224 return SYNCML_DM_IO_FAILURE; 225 } 226 /* Close the file */ 227 if (fileHandle.close() != SYNCML_DM_SUCCESS) 228 return SYNCML_DM_IO_FAILURE; 229 230 return SYNCML_DM_SUCCESS; 231 } 232 233 /*================================================================================================== 234 235 236 Function: SyncML_DM_WBXMLArchive::deserialize 237 238 Description: Deserializes a tree in the filesystem to the memory tree 239 240 ==================================================================================================*/ 241 242 SYNCML_DM_RET_STATUS_T 243 SyncML_DM_WBXMLArchive::deserialize(DMTree * pTree, 244 BOOLEAN bIsReload) 245 { 246 SYNCML_DM_RET_STATUS_T ret_stat = SYNCML_DM_SUCCESS; 247 248 #ifdef DM_PROFILER_ENABLED 249 DMString strCaption = "deserialize "; 250 strCaption += getURI(); strCaption += ", \""; 251 strCaption += m_path; strCaption += "\""; 252 DM_PROFILE( strCaption ); 253 #endif 254 255 if ( !rootTreeNode ) 256 return SYNCML_DM_FAIL; 257 258 oEventLogger.Reset(); 259 260 if ( !rootTreeNode->IsSkeletonNode() ) 261 { 262 if ( bIsReload ) 263 m_pTree->UnloadArchive(rootTreeNode); 264 else 265 return SYNCML_DM_SUCCESS; 266 } 267 268 DMPluginManager & oPluginManager = m_pTree->GetPluginManager(); 269 270 ret_stat = deserializeFile( pTree, m_strWFSFileName, true ); 271 272 if ( ret_stat == SYNCML_DM_FILE_NOT_FOUND ) 273 setWritableExist( FALSE ); 274 else 275 { 276 setWritableExist( TRUE ); 277 return oPluginManager.UpdatePluginNodes(m_pURI); 278 } 279 280 for ( int nFS = 0; nFS < m_pEnv->GetRFSCount(); nFS++ ) 281 { 282 DMString sFile; 283 m_pEnv->GetRFSFullPath(nFS,m_path,sFile); 284 if ( deserializeFile( pTree, sFile, false ) == SYNCML_DM_SUCCESS ) 285 ret_stat = SYNCML_DM_SUCCESS; // at least one file was successfully loaded 286 } 287 288 return oPluginManager.UpdatePluginNodes(m_pURI); 289 } 290 291 SYNCML_DM_RET_STATUS_T SyncML_DM_WBXMLArchive::deserializeFile( 292 DMTree* pTree, 293 CPCHAR szFileName, 294 BOOLEAN bWFS) 295 { 296 if (!XPL_FS_Exist(szFileName)) 297 return SYNCML_DM_FILE_NOT_FOUND; 298 299 SYNCML_DM_RET_STATUS_T ret_stat = SYNCML_DM_SUCCESS; 300 301 /* Create a file handle for the file to be deserialized */ 302 DMFileHandler fileHandle(szFileName); 303 SYNCML_DM_RET_STATUS_T openstat = fileHandle.open(XPL_FS_FILE_READ); 304 305 /* If file cannot be opened, leave now */ 306 if(openstat == SYNCML_DM_COMMAND_NOT_ALLOWED) { 307 return openstat; 308 } 309 else if (openstat != SYNCML_DM_SUCCESS) { 310 return SYNCML_DM_FILE_NOT_FOUND; /* Assume this is the underlying reason */ 311 } 312 313 m_permission |= XPL_FS_RDONLY_MODE; 314 315 /* Create a reader utility class for the reading of tree data */ 316 SyncML_DM_WBXMLReader reader(&fileHandle); 317 318 /* Working variable */ 319 UINT8 bYte; 320 321 /* Read a WBXML header from the file */ 322 if(reader.readHeader() != SYNCML_DM_SUCCESS) 323 { 324 fileHandle.close(); 325 return SYNCML_DM_IO_FAILURE; 326 } 327 328 /* Read and verify the MgmtTree start tag */ 329 if(reader.readByte(&bYte) != SYNCML_DM_SUCCESS) 330 { 331 fileHandle.close(); 332 return SYNCML_DM_IO_FAILURE; 333 } 334 if(bYte != (TREE_START_TAG | TAG_CONTENT_MASK)) 335 { 336 fileHandle.close(); 337 return SYNCML_DM_IO_FAILURE; 338 } 339 340 /* Read the first byte of data, expected to be END_TAG or NODE_START_TAG. 341 * The byte read will be parsed in the upcoming loop. 342 * If the byte is not the NODE_START_TAG with content, there is no 343 * tree to parse or there is an error (we assume error here). 344 */ 345 if(reader.readByte(&bYte) != SYNCML_DM_SUCCESS 346 || bYte != (SyncML_DM_WBXMLArchive::NODE_START_TAG 347 | SyncML_DM_WBXMLArchive::TAG_CONTENT_MASK)) 348 { 349 fileHandle.close(); 350 return SYNCML_DM_IO_FAILURE; 351 } 352 353 /* The properties data structure */ 354 DMAddNodeProp props; 355 356 DMNode* pNode = rootTreeNode->GetParent(); // can be null for '.'; otherwise is valid parent 357 358 /* Loop until an internal break occurs (hopefully, not until the last END_TAG */ 359 while(1) 360 { 361 /* If the read byte is an END_TAG... */ 362 if(bYte == END_TAG) 363 { 364 365 if ( pNode == rootTreeNode ) 366 break; // end of subtree 367 368 if ( !pNode || !pNode->GetParent() ){ 369 XPL_LOG_DM_TMN_Error((" ! Unexpected condition (node is null) inside deserialize\n")); 370 fileHandle.close(); 371 return SYNCML_DM_TREE_CORRUPT; // unexpected condition - looks like extra "end tag" 372 } 373 374 pNode = pNode->GetParent(); 375 376 /* Get the next byte after the END_TAG */ 377 ret_stat=reader.readByte(&bYte); 378 if(ret_stat != SYNCML_DM_SUCCESS) { 379 XPL_LOG_DM_TMN_Error((" ! Error ret_stat=%d\n", ret_stat)); 380 fileHandle.close(); 381 return SYNCML_DM_IO_FAILURE; 382 } 383 } 384 else 385 if(bYte == (NODE_START_TAG | TAG_CONTENT_MASK)) 386 { 387 388 /* This method reads in the node property data as well as 389 * the byte that signaled the end of the node. 390 * It allocates a props structure we are responsible for, 391 * It also sets props->pbURI to NULL. 392 */ 393 if(reader.readNode(&props, &bYte) != SYNCML_DM_SUCCESS) 394 { 395 fileHandle.close(); 396 return SYNCML_DM_IO_FAILURE; 397 } 398 399 /* Add the node to the tree */ 400 401 ret_stat = pTree->AddNode(&pNode, props); 402 403 if (ret_stat != SYNCML_DM_SUCCESS) 404 break; 405 406 } 407 else 408 { 409 /* Invalid byte read */ 410 ret_stat = SYNCML_DM_TREE_CORRUPT; 411 break; 412 } 413 }/* End while */ 414 415 fileHandle.close(); 416 XPL_LOG_DM_TMN_Debug(("End of deserialize ret_stat=%d\n", ret_stat)); 417 418 //set time stamp to emmory file 419 if ( bWFS ) 420 serializeDone(); 421 422 return ret_stat; 423 } 424 425 /*================================================================================================== 426 427 Function: SyncML_DM_WBXMLArchive::getLastModifiedTime 428 429 Description: Retrieves the last modification time of the archive 430 431 ==================================================================================================*/ 432 433 XPL_CLK_CLOCK_T 434 SyncML_DM_WBXMLArchive::getLastModifiedTime() 435 { 436 XPL_CLK_CLOCK_T lastModified=XPL_FS_GetModTime(m_strWFSFileName); 437 return lastModified; 438 } 439 440 XPL_CLK_CLOCK_T SyncML_DM_WBXMLArchive::getLastSavedTime() 441 { 442 return lastSavedTime; 443 } 444 445 void SyncML_DM_WBXMLArchive::serializeDone() 446 { 447 lastSavedTime=XPL_FS_GetModTime(m_strWFSFileName); 448 oEventLogger.OnTreeSaved(); 449 } 450 451 // returns TRUE if permission is allowed 452 BOOLEAN 453 SyncML_DM_WBXMLArchive::verifyPermission(XPL_FS_OPEN_MODE_T permission) const 454 { 455 // XPL_LOG_DM_TMN_Debug(("m_permission=%d, filename=%s\n", m_permission, m_strWFSFileName.c_str())); 456 return (m_permission & permission); 457 } 458 459 460 #ifdef LOB_SUPPORT 461 /*================================================================================================== 462 463 Function: SyncML_DM_WBXMLArchive::commitESN 464 465 Description: Commit all changes for ESN 466 467 ==================================================================================================*/ 468 SYNCML_DM_RET_STATUS_T 469 SyncML_DM_WBXMLArchive::commitESN(DMTree* tree) 470 { 471 SYNCML_DM_SERIALIZATION_STATUS_T ser_ret_stat; 472 SYNCML_DM_RET_STATUS_T retStatus = SYNCML_DM_SUCCESS; 473 474 //Remove commit log file 475 if(commitLog != NULL) 476 { 477 //Commit log file name = Path + "commit" + null 478 DMString strTempFilePath = m_strWFSFileName; 479 strTempFilePath += DMFileHandler::COMMIT_LOG_EXTENSION; 480 commitLog->playLog(strTempFilePath.c_str()); 481 delete commitLog; 482 commitLog = NULL; 483 484 /* Create the path string for the temp file */ 485 if (this->rootTreeNode==NULL) 486 return SYNCML_DM_SKIP_SUBTREE; 487 488 tree->InitSerializationList(this->rootTreeNode); 489 490 DMNode * pRetNode = NULL; 491 /* Loop on the nodes returned by the tree and node manager */ 492 INT32 nEndTagsNumber = 0; 493 while((ser_ret_stat = tree->GetSerializationListNextItem(&pRetNode, nEndTagsNumber)) == SYNCML_DM_SERIALIZATION_SUCCESS) 494 { 495 // Special case for ESN 496 if(pRetNode->IsESN()) 497 { 498 // Convert to ESN pointer 499 DMDefaultESN *tempESN = reinterpret_cast< DMDefaultESN *>(pRetNode); 500 // Call commit command handler 501 retStatus = tempESN->Commit(); 502 if(retStatus != SYNCML_DM_SUCCESS) 503 return retStatus; 504 } 505 }/* End while */ 506 } 507 return SYNCML_DM_SUCCESS; 508 } 509 /*================================================================================================== 510 511 Function: SyncML_DM_WBXMLArchive::rollback 512 513 Description: Rollback all changes for ESN 514 515 ==================================================================================================*/ 516 SYNCML_DM_RET_STATUS_T 517 SyncML_DM_WBXMLArchive::rollbackESN(DMTree* tree) 518 { 519 SYNCML_DM_SERIALIZATION_STATUS_T ser_ret_stat; 520 SYNCML_DM_RET_STATUS_T retStatus = SYNCML_DM_SUCCESS; 521 522 //Remove commit log file 523 if(commitLog != NULL) 524 { 525 commitLog->RemoveLog(); 526 delete commitLog; 527 commitLog = NULL; 528 529 /* Create the path string for the temp file */ 530 if (this->rootTreeNode==NULL) 531 return SYNCML_DM_SKIP_SUBTREE; 532 533 tree->InitSerializationList(this->rootTreeNode); 534 535 DMNode * pRetNode = NULL; 536 /* Loop on the nodes returned by the tree and node manager */ 537 INT32 nEndTagsNumber = 0; 538 while((ser_ret_stat = tree->GetSerializationListNextItem(&pRetNode, nEndTagsNumber)) == SYNCML_DM_SERIALIZATION_SUCCESS) 539 { 540 // Special case for ESN 541 if(pRetNode->IsESN()) 542 { 543 // Convert to ESN pointer 544 DMDefaultESN *tempESN = reinterpret_cast< DMDefaultESN *>(pRetNode); 545 // Call rollback command handler 546 retStatus = tempESN->Rollback(); 547 if(retStatus != SYNCML_DM_SUCCESS) 548 return retStatus; 549 } 550 }/* End while */ 551 } 552 return SYNCML_DM_SUCCESS; 553 } 554 /*================================================================================================== 555 556 Function: SyncML_DM_WBXMLArchive::GetCommitLogHandler 557 558 Description: Retrieves the commit log handler 559 560 ==================================================================================================*/ 561 SyncML_Commit_Log* SyncML_DM_WBXMLArchive::GetCommitLogHandler() 562 { 563 if(commitLog == NULL) 564 { commitLog = new SyncML_Commit_Log(); 565 if(this->commitLog != NULL) 566 { 567 //Commit log file name = Path + "commit" + null 568 DMString strTempFilePath = m_strWFSFileName; 569 strTempFilePath += DMFileHandler::COMMIT_LOG_EXTENSION; 570 if(this->commitLog->InitLog(strTempFilePath.c_str()) != SYNCML_DM_SUCCESS) 571 { 572 delete commitLog; 573 commitLog = NULL; 574 } 575 } 576 } 577 return commitLog; 578 } 579 /*================================================================================================== 580 581 Function: SyncML_DM_WBXMLArchive::CloseCommitLog 582 583 Description: Close the commit log file 584 585 ==================================================================================================*/ 586 SYNCML_DM_RET_STATUS_T SyncML_DM_WBXMLArchive::CloseCommitLog() 587 { 588 SYNCML_DM_RET_STATUS_T ret_stat = SYNCML_DM_SUCCESS; 589 if(commitLog != NULL) 590 ret_stat = commitLog->CloseLog(); 591 return ret_stat; 592 } 593 /*================================================================================================== 594 595 Function: SyncML_DM_WBXMLArchive::PlayCommitLog 596 597 Description: Free the commit log handler 598 599 ==================================================================================================*/ 600 SYNCML_DM_RET_STATUS_T SyncML_DM_WBXMLArchive::PlayCommitLog() 601 { 602 SYNCML_DM_RET_STATUS_T ret_stat = SYNCML_DM_SUCCESS; 603 if(commitLog == NULL) 604 GetCommitLogHandler(); 605 if(commitLog != NULL) 606 { 607 commitLog->playLog(); 608 commitLog->RemoveLog(); 609 delete commitLog; 610 commitLog = NULL; 611 } 612 return ret_stat; 613 } 614 #endif 615