Home | History | Annotate | Download | only in src
      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