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 /*================================================================================================== 18 19 Source Name: dmConfigManager.cc 20 21 General Description: Implementation of the DMConfigManager class 22 23 ==================================================================================================*/ 24 25 #include "dm_tree_class.H" 26 #include "dmConfigManager.h" 27 #include "dmLockingHelper.h" 28 #include "dm_uri_utils.h" 29 #include "xpl_Logger.h" 30 31 DMConfigManager::DMConfigManager() 32 : m_pEnv( NULL ), 33 m_pTree( NULL ) 34 { 35 m_bChanged = FALSE; 36 m_bLoaded = FALSE; 37 m_nLastLoadTimeStamp = 0; 38 } 39 40 DMConfigManager::~DMConfigManager() 41 { 42 } 43 44 45 46 47 SYNCML_DM_RET_STATUS_T DMConfigManager::Init( CEnv* env, 48 DMTree* tree, 49 SYNCML_DM_FILE_TYPE_T fileType) 50 { 51 if( !env || !tree ) return SYNCML_DM_FAIL; 52 53 m_pEnv = env; 54 m_pTree = tree; 55 m_efileType = fileType; 56 57 GetFileName(m_strFileName); 58 if ( !XPL_FS_Exist(m_strFileName) ) 59 { 60 DMFileHandler tf(m_strFileName); 61 tf.open(XPL_FS_FILE_WRITE); 62 tf.close(); 63 } 64 return SYNCML_DM_SUCCESS; 65 } 66 67 SYNCML_DM_RET_STATUS_T DMConfigManager::DeInit() 68 { 69 m_bChanged = FALSE; 70 m_bLoaded = FALSE; 71 m_nLastLoadTimeStamp = 0; 72 m_strFileName = NULL; 73 m_pEnv = NULL; 74 m_pTree = NULL; 75 ClearMemory(); 76 return SYNCML_DM_SUCCESS; 77 } 78 79 80 81 SYNCML_DM_RET_STATUS_T 82 DMConfigManager::DeserializeDictionary(DMFileHandler& dmf, 83 DMMap<INT32, DMString>& aDict) 84 { 85 86 DMString strLineBuffer; 87 char *line = strLineBuffer.AllocateBuffer(DM_MAX_CONFIG_LINE); 88 89 if ( !line ) 90 { 91 XPL_LOG_DM_TMN_Error(("Device memory is full")); 92 return SYNCML_DM_DEVICE_FULL; 93 } 94 95 while ( GetNextLine(dmf, line) && line[0] ) 96 { 97 DMString strID, strSrv = line; 98 99 DmStringParserGetItem( strID, strSrv, ':' ); 100 aDict.put( DmAtoi(strID), strSrv ); 101 } 102 103 return SYNCML_DM_SUCCESS; 104 105 } 106 107 108 SYNCML_DM_RET_STATUS_T DMConfigManager::Deserialize() 109 { 110 // check if we have latest copy in memory already 111 XPL_CLK_CLOCK_T lastLoadTimeStamp = XPL_FS_GetModTime(m_strFileName.c_str()); 112 if ( m_bLoaded && lastLoadTimeStamp == m_nLastLoadTimeStamp ) 113 return SYNCML_DM_SUCCESS; 114 115 DMGlobalLockHelper oGlobalLock; // protect serialize/recovery from multi process access 116 117 CheckRecovery(); 118 119 ClearMemory(); 120 121 SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS; 122 123 DMFileHandler evtFile(m_strFileName); 124 125 if ( evtFile.open(XPL_FS_FILE_READ) != SYNCML_DM_SUCCESS ) 126 { 127 XPL_LOG_DM_TMN_Error(("Failed to open config file, %s\n", m_strFileName.c_str())); 128 return SYNCML_DM_IO_FAILURE; 129 } 130 131 if ( !evtFile.size() ) 132 return SYNCML_DM_SUCCESS; 133 134 DMMap<INT32, DMString> aDict; 135 dm_stat = DeserializeDictionary(evtFile, aDict); 136 if ( dm_stat != SYNCML_DM_SUCCESS ) 137 return dm_stat; 138 139 DMString strLineBuffer; 140 char *line = strLineBuffer.AllocateBuffer(DM_MAX_CONFIG_LINE); 141 UINT16 lineNo = 0; 142 143 if ( !line ) 144 { 145 XPL_LOG_DM_TMN_Error(("Device memory is full")); 146 return SYNCML_DM_DEVICE_FULL; 147 } 148 149 while ( GetNextLine(evtFile, line ) ) 150 { 151 lineNo++; 152 153 DMString strPath; 154 if ( !GetPath( line, strPath ) ) 155 continue; 156 157 // get the value 158 if (!GetNextLine(evtFile, line )) 159 { 160 XPL_LOG_DM_TMN_Error(("config file format error at line %d - unexpected end of file\n \n", lineNo )); 161 dm_stat = SYNCML_DM_IO_FAILURE; 162 break; // end of file 163 } 164 165 dm_stat = Add(strPath, line,aDict); 166 if ( dm_stat != SYNCML_DM_SUCCESS ) 167 break; 168 } 169 170 evtFile.close(); 171 m_bChanged = FALSE; 172 m_nLastLoadTimeStamp = lastLoadTimeStamp; 173 m_bLoaded = TRUE; 174 return SYNCML_DM_SUCCESS; 175 } 176 177 178 BOOLEAN 179 DMConfigManager::GetPath( char* line, 180 DMString& strPath ) 181 { 182 char* startP = DmStrchr( line, '[' ); 183 if (!startP) 184 return FALSE; 185 186 char* endP = DmStrchr(line, ']' ); 187 188 if ( !endP || endP < startP ) { 189 XPL_LOG_DM_TMN_Error(("config file format error \n %s\n", line)); 190 return FALSE; 191 } 192 193 // remove [], add '.' if necessary to create a full uri 194 *endP = 0; 195 startP++; 196 197 if ( *startP != '.' ) 198 strPath = "."; 199 200 strPath += startP; 201 return TRUE; 202 } 203 204 205 void DMConfigManager::CheckRecovery() const 206 { 207 DMString strTempFile = m_strFileName; 208 DMString strBakFile = m_strFileName; 209 UINT8 state = 0; 210 211 strTempFile += DMFileHandler::TEMP_FILE_EXTENSION; 212 strBakFile += DMFileHandler::BAK_FILE_EXTENSION; 213 214 #define TEMP_EXISTS 1 // .temp file exists state bit 215 #define BAK_EXISTS 2 // .bak file exists state bit 216 217 if (XPL_FS_Exist(strTempFile.c_str())) 218 state |= TEMP_EXISTS; 219 220 if (XPL_FS_Exist(strBakFile.c_str())) 221 state |= BAK_EXISTS; 222 223 switch(state) { 224 case (TEMP_EXISTS | BAK_EXISTS): // case C 225 if (XPL_FS_Rename(strBakFile.c_str(), m_strFileName.c_str()) == XPL_FS_RET_FAIL) 226 break; 227 //continue to delete .temp files 228 229 case TEMP_EXISTS: // case B 230 XPL_FS_Remove(strTempFile.c_str()); 231 break; 232 233 case BAK_EXISTS: // case D 234 XPL_FS_Remove(strBakFile.c_str()); 235 break; 236 237 default: // no action needed 238 break; 239 } 240 } 241 242 BOOLEAN 243 DMConfigManager::GetNextLine(DMFileHandler& dmf, 244 char *line) 245 246 { 247 248 line[0]= 0; 249 250 while (!dmf.iseof()) { 251 dmf.fgets(line, DM_MAX_CONFIG_LINE); 252 253 if(*line != '#') 254 return TRUE; 255 } 256 257 return FALSE; 258 } 259 260 261 SYNCML_DM_RET_STATUS_T DMConfigManager::Serialize() 262 { 263 if ( !m_bChanged ) 264 return SYNCML_DM_SUCCESS; 265 266 DMGlobalLockHelper oGlobalLock; // protect serialize/recovery from multi process access 267 268 SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS; 269 270 DMString strTmpName = m_strFileName; 271 DMString strBakName = m_strFileName; 272 273 strTmpName += DMFileHandler::TEMP_FILE_EXTENSION; 274 strBakName += DMFileHandler::BAK_FILE_EXTENSION; 275 276 DMFileHandler tf(strTmpName.c_str()); 277 278 if (tf.open(XPL_FS_FILE_WRITE) != SYNCML_DM_SUCCESS) { 279 XPL_LOG_DM_TMN_Error(("Error opening %s\n", strTmpName.c_str())); 280 return SYNCML_DM_IO_FAILURE; 281 } 282 283 if ( !m_aConfig.size() ) 284 { 285 if (tf.close() != SYNCML_DM_SUCCESS) 286 return SYNCML_DM_IO_FAILURE; 287 XPL_FS_Rename(m_strFileName.c_str(), strBakName.c_str()); 288 XPL_FS_Rename(strTmpName.c_str(), m_strFileName.c_str()); 289 XPL_FS_Remove(strBakName.c_str()); 290 m_nLastLoadTimeStamp = XPL_FS_GetModTime(m_strFileName.c_str()); 291 m_bChanged = FALSE; 292 m_bLoaded = TRUE; 293 return SYNCML_DM_SUCCESS; 294 } 295 296 DMMap<DMString, INT32> aDict; 297 UpdateDictionary(aDict); 298 299 dm_stat = SerializeDictionary(tf,aDict); 300 if ( dm_stat != SYNCML_DM_SUCCESS ) 301 return dm_stat; 302 303 // empty line between dictionary and data 304 if ( tf.write( "\n", 1 ) != SYNCML_DM_SUCCESS ) 305 return SYNCML_DM_IO_FAILURE; 306 307 for ( INT32 index=0; index<m_aConfig.size(); index++) 308 { 309 310 #ifdef TEST_DM_RECOVERY 311 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "PF1") == 0)) 312 { 313 printf("Type Ctrl-C to simulate Power Fail ...\n"); 314 sleep(30); 315 } 316 #endif 317 PDMConfigItem & oConfigItem = m_aConfig[index]; 318 if ( oConfigItem->Serialize( tf, aDict ) != SYNCML_DM_SUCCESS ) 319 return SYNCML_DM_IO_FAILURE; 320 } 321 322 if (tf.close() != SYNCML_DM_SUCCESS) 323 return SYNCML_DM_IO_FAILURE; 324 325 #ifdef TEST_DM_RECOVERY 326 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "PF2") == 0)) 327 { 328 printf("Type Ctrl-C to simulate Power Fail ...\n"); 329 sleep(30); 330 } 331 #endif 332 333 // rename to .bak file 334 XPL_FS_Rename(m_strFileName.c_str(), strBakName.c_str()); 335 #ifdef TEST_DM_RECOVERY 336 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "PF3") == 0)) 337 { 338 printf("Type Ctrl-C to simulate Power Fail ...\n"); 339 sleep(30); 340 } 341 #endif 342 343 // rename .temp file to original name 344 XPL_FS_Rename(strTmpName.c_str(), m_strFileName.c_str()); 345 #ifdef TEST_DM_RECOVERY 346 if ((power_fail_point != NULL) && (DmStrcmp(power_fail_point, "PF4") == 0)) { 347 printf("Type Ctrl-C to simulate Power Fail ...\n"); 348 sleep(30); 349 } 350 #endif 351 352 // delete .bak file 353 XPL_FS_Remove(strBakName.c_str()); 354 355 m_nLastLoadTimeStamp = XPL_FS_GetModTime(m_strFileName.c_str()); 356 m_bChanged = FALSE; 357 m_bLoaded = TRUE; 358 359 return SYNCML_DM_SUCCESS ; 360 361 } 362 363 364 SYNCML_DM_RET_STATUS_T 365 DMConfigManager::SerializeDictionary( DMFileHandler& dmf, 366 const DMMap<DMString, INT32>& aDict) 367 { 368 369 char szNumBuffer[20] = ""; // big enough to hold a number 370 for ( DMMap<DMString, INT32>::POS pos = aDict.begin(); pos < aDict.end(); pos++ ) 371 { 372 INT32 nLen = sprintf( szNumBuffer, "%d:", aDict.get_value(pos) ); 373 if ( dmf.write( szNumBuffer, nLen ) != SYNCML_DM_SUCCESS || 374 dmf.write( aDict.get_key(pos).c_str(), aDict.get_key(pos).length()) != SYNCML_DM_SUCCESS || 375 dmf.write( "\n", 1 ) != SYNCML_DM_SUCCESS ) 376 return SYNCML_DM_IO_FAILURE; 377 } 378 379 return SYNCML_DM_SUCCESS; 380 381 } 382 383 384 SYNCML_DM_RET_STATUS_T DMConfigManager::Revert() 385 { 386 if ( !m_bLoaded || !m_bChanged ) 387 return SYNCML_DM_SUCCESS; 388 389 m_bChanged = false; 390 m_bLoaded = false; 391 return Deserialize(); 392 } 393 394 395 void DMConfigManager::CheckLocking() 396 { 397 if ( !m_bChanged ) 398 { 399 m_pTree->GetLockContextManager().InsureFileLocked(m_efileType); 400 Deserialize(); 401 } 402 } 403 404 405 INT32 DMConfigManager::Find(CPCHAR szPath) const 406 { 407 for (INT32 index=0; index<m_aConfig.size(); index ++) 408 { 409 const PDMConfigItem & pItem = m_aConfig[index]; 410 if ( pItem->GetPath() == szPath ) 411 { 412 return index; 413 } 414 } 415 return -1; 416 417 } 418 419 420 INT32 DMConfigManager::Find(CPCHAR szPath, PDMConfigItem & oConfigItem) const 421 { 422 INT32 index = Find(szPath); 423 if ( index != -1 ) 424 oConfigItem = m_aConfig[index]; 425 return index; 426 427 } 428 429 430 void DMConfigManager::ClearMemory() 431 { 432 m_aConfig.clear(); 433 } 434 435 436 SYNCML_DM_RET_STATUS_T 437 DMConfigManager::Add(const DMString & szPath, 438 CPCHAR szConfig, 439 const DMMap<INT32, DMString>& aDict) 440 { 441 SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS; 442 443 if ( Find(szPath) != -1 ) 444 return SYNCML_DM_FAIL; 445 446 DMConfigItem * pConfigItem = AllocateConfigItem(); 447 448 if ( !pConfigItem ) 449 return SYNCML_DM_DEVICE_FULL; 450 451 dm_stat = pConfigItem->Set( szPath, szConfig, aDict ); 452 if ( dm_stat != SYNCML_DM_SUCCESS ) 453 { 454 delete pConfigItem; 455 return dm_stat; 456 } 457 458 m_aConfig.push_back(PDMConfigItem(pConfigItem)); 459 return SYNCML_DM_SUCCESS; 460 461 } 462 463 464 void DMConfigManager::UpdateDictionary(DMMap<DMString, INT32>& aDict) 465 { 466 467 for (INT32 index=0; index<m_aConfig.size(); index++) 468 { 469 PDMConfigItem & pConfigItem = m_aConfig[index]; 470 pConfigItem->UpdateDictionary( aDict ); 471 } 472 } 473 474 475 SYNCML_DM_RET_STATUS_T 476 DMConfigManager::Delete(CPCHAR szPath) 477 { 478 INT32 index = Find(szPath); 479 if ( index == -1 ) 480 return SYNCML_DM_NOT_FOUND; 481 482 CheckLocking(); 483 m_aConfig.remove(index); 484 m_bChanged = true; 485 486 return SYNCML_DM_SUCCESS; 487 488 } 489 490 491 SYNCML_DM_RET_STATUS_T 492 DMConfigManager::Get(CPCHAR szPath, 493 PDMConfigItem & pItem) const 494 { 495 496 if ( Find(szPath, pItem) == -1 ) 497 { 498 DMString szMDF; 499 SYNCML_DM_RET_STATUS_T dm_stat; 500 DMMetaDataManager & m_oMDFObj = m_pTree->GetMetaDataManager(); 501 dm_stat = m_oMDFObj.GetPath(szPath, szMDF); 502 503 if ( dm_stat != SYNCML_DM_SUCCESS ) 504 return dm_stat; 505 506 if ( szMDF != szPath ) 507 { 508 if ( Find(szMDF, pItem) == -1 ) 509 return SYNCML_DM_NOT_FOUND; 510 } 511 else 512 return SYNCML_DM_NOT_FOUND; 513 } 514 515 return SYNCML_DM_SUCCESS; 516 } 517