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 *  DESCRIPTION:
19 *      The dm_tree_plugin_util.cc file contains helper functions
20 *      for plug-in support
21 */
22
23#include "xpl_Logger.h"
24#include "dmtTreeImpl.hpp"
25#include "dm_tree_plugin_root_node_class.H"
26#include "dm_tree_plugin_util.H"
27#include "dm_tree_util.h"
28#include "SyncML_DM_WBXMLArchive.H"
29#include "SyncML_PlugIn_WBXMLLog.H"
30#include "dm_uri_utils.h"
31
32#ifndef min
33#define min(a,b) (((a) < (b)) ? (a) : (b))
34#endif
35
36SYNCML_DM_RET_STATUS_T
37DmCheckNodeConstraint(const PDMPlugin & pPlugin) ;
38
39SYNCML_DM_RET_STATUS_T
40DmCheckMultiNodeConstraint(const PDMPlugin & pPlugin, CPCHAR path, CPCHAR remain, const PDmtTree & tree);
41
42SYNCML_DM_RET_STATUS_T DmRemoveTempfile(DMString &dirName)
43{
44
45    SYNCML_DM_RET_STATUS_T ret_code = SYNCML_DM_SUCCESS;
46    XPL_FS_SHANDLE_T search_handle;
47    DMString strFileNameBuffer;
48    char *file_name = strFileNameBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH);
49
50    if (file_name == NULL)
51      return SYNCML_DM_DEVICE_FULL;
52
53    search_handle = XPL_FS_StartSearch(dirName, DMFileHandler::MIDDLE_FILE_EXTENSION, TRUE, NULL);
54    if ( search_handle == XPL_FS_SHANDLE_INVALID)
55        return SYNCML_DM_IO_FAILURE;
56
57   //Loop through all .temp files in the directory
58    memset(file_name,0,XPL_FS_MAX_FILE_NAME_LENGTH);
59    while ( XPL_FS_GetSearchResult(search_handle,file_name) != XPL_FS_RET_NOT_FOUND )
60    {
61
62	DMFileHandler fileHandler(file_name);
63	ret_code = fileHandler.open(XPL_FS_FILE_RDWR);
64	// Remove temporary ESN file
65	if(ret_code == SYNCML_DM_SUCCESS)
66		fileHandler.deleteFile();
67     }
68     XPL_FS_EndSearch(search_handle);
69    return ret_code;
70}
71
72SYNCML_DM_RET_STATUS_T DMTree::ReadCommandFromFile( DMFileHandler    *fileHandle,
73                                                    DMBuffer&        cmdURI )
74{
75  SYNCML_DM_RET_STATUS_T  ret_code = SYNCML_DM_FAIL;
76  SyncML_DM_WBXMLReader*  reader = new SyncML_DM_WBXMLReader( fileHandle );
77
78  if( reader ) for( ; ; )
79  {
80    ret_code = SYNCML_DM_IO_FAILURE;
81    if(fileHandle->seek(XPL_FS_SEEK_SET, sizeof(INT32) + 2) != XPL_FS_RET_SUCCESS) break;
82
83    // Read URI
84    ret_code = reader->readOpaque( &cmdURI );
85    if( SYNCML_DM_SUCCESS != ret_code ) break;
86
87    //Read END_TAG
88    UINT8  bYte = 0;
89    ret_code = reader->readByte( &bYte );
90    if( SYNCML_DM_SUCCESS != ret_code ) break;
91
92    ret_code = SYNCML_DM_IO_FAILURE;
93    if( bYte != SyncML_DM_WBXMLArchive::END_TAG ) break;
94
95    ret_code = SYNCML_DM_SUCCESS;
96    break;
97  }
98
99  if( reader )
100  {
101    delete reader;
102    reader = NULL;
103  }
104
105  return ret_code;
106}
107
108SYNCML_DM_RET_STATUS_T DMTree::RecoverPluginFromFile( const DMString&  file_bak_name )
109{
110  SYNCML_DM_RET_STATUS_T  ret_code = SYNCML_DM_FAIL;
111  DMFileHandler           *fileHandle = new DMFileHandler( file_bak_name );
112
113  if( fileHandle )
114  {
115    BOOLEAN delete_file = FALSE;
116
117    if(fileHandle->open(XPL_FS_FILE_RDWR) != SYNCML_DM_SUCCESS)
118    {
119      // DM: Ignore files that cannot be opened ?
120      ret_code = SYNCML_DM_SUCCESS;
121    }
122    else
123    {
124      delete_file = TRUE;
125
126      DMBuffer cmdURI;
127      ret_code = ReadCommandFromFile( fileHandle, cmdURI );
128
129      if( ret_code == SYNCML_DM_SUCCESS )
130      {
131        PDMPlugin pPlugin = m_oPluginManager.FindPlugin(SYNCML_DM_DATA_PLUGIN, (CPCHAR)cmdURI.getBuffer());
132
133        if (pPlugin != NULL)
134        {
135          PDmtAPIPluginTree  pluginTree;
136          ret_code=pPlugin->GetTree((CPCHAR) cmdURI.getBuffer(), pluginTree);
137
138          if(ret_code == SYNCML_DM_SUCCESS)
139          {
140            PDmtRWPluginTree ptrRWTree = (DmtRWPluginTree *) ((DmtTree *)pluginTree);
141            ret_code = ptrRWTree->setLogFileHandle(fileHandle);
142
143            if( ret_code == SYNCML_DM_SUCCESS)
144            {
145              ret_code = ptrRWTree->Rollback();
146
147              // DM: hands-off from file
148              fileHandle = NULL;
149            }
150          }
151        }
152      }
153    }
154
155    if( fileHandle )
156    {
157      if( delete_file )
158      {
159        fileHandle->deleteFile();
160      }
161
162      delete fileHandle;
163      fileHandle = NULL;
164    }
165  }
166
167  return ret_code;
168}
169
170SYNCML_DM_RET_STATUS_T DMTree::RecoverPlugin()
171{
172
173  SYNCML_DM_RET_STATUS_T  ret_code = SYNCML_DM_SUCCESS;
174  DMString                strFileNameBuffer;
175  DMString                strFileBakNameBuffer;
176
177  char                    *file_name = strFileNameBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH);
178  char                    *file_bak_name = strFileBakNameBuffer.AllocateBuffer(XPL_FS_MAX_FILE_NAME_LENGTH);
179
180  if ( !file_name || !file_bak_name )
181    return SYNCML_DM_DEVICE_FULL;
182
183  DMString logtdir;
184  m_oEnv.GetWFSFullPath( NULL, logtdir );
185
186  XPL_FS_SHANDLE_T search_handle = XPL_FS_StartSearch(logtdir, DMFileHandler::LOG_FILE_EXTENSION, TRUE, NULL);
187  if ( search_handle == XPL_FS_SHANDLE_INVALID)
188      return SYNCML_DM_IO_FAILURE;
189
190 //Loop through all .log files in the directory
191  memset(file_name, 0, XPL_FS_MAX_FILE_NAME_LENGTH );
192  memset(file_bak_name, 0, XPL_FS_MAX_FILE_NAME_LENGTH );
193
194  int nExtLength = DmStrlen( DMFileHandler::LOG_FILE_EXTENSION );
195
196  while ( XPL_FS_GetSearchResult(search_handle, file_name) != XPL_FS_RET_NOT_FOUND )
197  {
198    int nFileNameLen = DmStrlen(file_name);
199
200    if ( file_name[0] == 0 || nFileNameLen < 5 ) continue;
201
202    DmStrncpy(file_bak_name, file_name, nFileNameLen - nExtLength );
203    DmStrcat(file_bak_name, DMFileHandler::MIDDLE_FILE_EXTENSION);
204
205    if( XPL_FS_RET_SUCCESS != XPL_FS_Rename( file_name, file_bak_name ) )
206    {
207      ret_code = SYNCML_DM_IO_FAILURE;
208      continue;
209    }
210
211    ret_code = RecoverPluginFromFile( file_bak_name );
212    // DM: continue even if there is an error ( exactly as in original version of code )
213  }
214
215  XPL_FS_EndSearch(search_handle);
216  return ret_code;
217
218}
219
220SYNCML_DM_RET_STATUS_T
221DmExecutePlugin(CPCHAR path,
222                                CPCHAR args,
223                                CPCHAR szCorrelator,
224                                DMString & oResult)
225{
226   SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_FAIL;
227   DMPluginManager & oPluginManager = dmTreeObj.GetPluginManager();
228
229   XPL_LOG_DM_TMN_Debug((" DmExecutePlugin find plugin\n"));
230   PDMPlugin pPlugin = oPluginManager.FindPlugin(SYNCML_DM_EXECUTE_PLUGIN, path);
231
232   if (pPlugin == NULL)
233   {
234        XPL_LOG_DM_TMN_Debug((" DmExecutePlugin plugin not found\n"));
235        return SYNCML_DM_FEATURE_NOT_SUPPORTED;
236   }
237
238   PDmtTree ptrTree( new DmtTreeImpl(FALSE) ); // readonly version of the tree
239
240   XPL_LOG_DM_TMN_Debug((" DmExecutePlugin plugin being executed...\n"));
241   return pPlugin->Execute(path,args,szCorrelator,ptrTree,oResult);
242}
243
244SYNCML_DM_RET_STATUS_T
245DmCallPluginFunction(CPCHAR szSessionRootURI,
246                                        FILESETTYPE nFileSet,
247                                        SYNCML_DM_COMMAND_T type)
248{
249    SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS;
250    DMPluginManager & oPluginManager = dmTreeObj.GetPluginManager();
251
252    DMPluginVector  plugins;
253    PDmtAPIPluginTree  pluginTree;
254
255    oPluginManager.GetPlugins(szSessionRootURI, SYNCML_DM_DATA_PLUGIN, plugins);
256
257    INT32 size = plugins.size();
258    for ( INT32 i=0; i<size; i++ )
259    {
260        PDMPlugin  plugin = plugins[i];
261        if(plugin->IsTreeEmpty())
262            continue;
263
264        dm_stat=plugin->GetTree(plugin->GetPath(), pluginTree);
265        if(dm_stat == SYNCML_DM_SUCCESS)
266        {
267            switch(type)
268            {
269                case SYNCML_DM_RELEASE:
270                    dm_stat = pluginTree->Flush();
271                    break;
272
273                case SYNCML_DM_ROLLBACK:
274                {
275                    FILESETTYPE sets = 0;
276
277                    SyncML_DM_Archiver&  archiver = dmTreeObj.GetArchiver();
278                    sets = archiver.getArchivesByURI(plugin->GetPath());
279                    sets &= nFileSet;
280
281                    if ( sets != 0 )
282                    {
283                        dm_stat = pluginTree->Rollback();
284                    }
285                }
286                    break;
287
288                case SYNCML_DM_COMMIT:
289                    dm_stat = pluginTree->Commit();
290                    break;
291
292                case SYNCML_DM_ATOMIC:
293                    dm_stat = pluginTree->Begin();
294                    break;
295           }
296         }
297
298         if (dm_stat != SYNCML_DM_SUCCESS)
299         {
300            if((dm_stat == SYNCML_DM_FEATURE_NOT_SUPPORTED)&&(type == SYNCML_DM_ATOMIC))
301                return dm_stat;
302            else
303               dm_stat = SYNCML_DM_SUCCESS;
304        }
305     }
306
307   XPL_LOG_DM_TMN_Debug((" DmCallPluginFunction retStat=%d\n", dm_stat));
308   return dm_stat;
309}
310
311SYNCML_DM_RET_STATUS_T
312DmCheckConstraint(CPCHAR szSessionRootURI,
313                                 FILESETTYPE * pFileSet,
314                                 FILESETTYPE * pFileSetToRollback)
315{
316    SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS;
317    SYNCML_DM_RET_STATUS_T dm_const_stat = SYNCML_DM_SUCCESS;
318
319    SyncML_DM_Archiver&  archiver = dmTreeObj.GetArchiver();
320    FILESETTYPE  numArchives = archiver.getNumArchives();
321    FILESETTYPE  i = 0;
322    FILESETTYPE  set = 1;
323
324
325    if ( pFileSet == NULL || pFileSetToRollback == NULL )
326        return SYNCML_DM_FAIL;
327
328    XPL_LOG_DM_TMN_Debug(("--- DmCheckConstraint for %s, pFileSet=0x%x, numArchives=%d\n", szSessionRootURI, *pFileSet, numArchives));
329
330    if ( !archiver.IsDirty(pFileSet) )
331    {
332        XPL_LOG_DM_TMN_Debug(("No archives are dirty\n"));
333        return dm_stat;
334    }
335
336    DMPluginVector  aSessionPlugins;
337
338    DMPluginManager & oPluginManager = dmTreeObj.GetPluginManager();
339    oPluginManager.GetPlugins(szSessionRootURI, SYNCML_DM_CONSTRAINT_PLUGIN, aSessionPlugins);
340
341    INT32 size = aSessionPlugins.size();
342    for (INT32 index=0; index< size; index++)
343    {
344        FILESETTYPE sets = 0;
345
346        CPCHAR strRootPath=(aSessionPlugins[index])->GetPath();
347
348        sets = archiver.getArchivesByURI(strRootPath);
349        sets = sets & (*pFileSet);
350        if ( sets )
351        {
352            dm_stat = DmCheckNodeConstraint(aSessionPlugins[index]);
353            if ( dm_stat != SYNCML_DM_SUCCESS )
354            {
355                for (i=0, set=1; i< numArchives;  i++, set = set <<1)
356                {
357                    if ( (sets & set) != 0 && ((*pFileSetToRollback) & set) == 0 )
358                    {
359                        (*pFileSetToRollback) |= set;
360                        (*pFileSet) &= ~ set;
361                    }
362                }
363                dm_const_stat = dm_stat;
364            }
365        }
366    }
367
368    if ( dm_const_stat != SYNCML_DM_SUCCESS )
369        dm_stat = dm_const_stat;
370
371    XPL_LOG_DM_TMN_Debug((" DmCheckConstraint retStat=%d\n", dm_stat));
372    return dm_stat;
373}
374
375
376
377SYNCML_DM_RET_STATUS_T
378DmCheckNodeConstraint(const PDMPlugin & pPlugin)
379{
380      SYNCML_DM_RET_STATUS_T dm_stat = SYNCML_DM_SUCCESS;
381      PDmtTree tree( new DmtTreeImpl(true) );
382
383      CPCHAR strPluginPath=pPlugin->GetPath();
384
385      if (  (DmStrchr(strPluginPath, '*')) == NULL)
386      {
387            dm_stat = (pPlugin)->CheckConstraint(strPluginPath,tree);
388      }
389      else
390      {
391            dm_stat = DmCheckMultiNodeConstraint(pPlugin,"",strPluginPath,tree);
392      }
393
394      if (dm_stat != SYNCML_DM_SUCCESS)
395            dm_stat = SYNCML_DM_CONSTRAINT_FAIL;
396
397     return dm_stat;
398
399}
400
401
402SYNCML_DM_RET_STATUS_T
403DmCheckMultiNodeConstraint(const PDMPlugin & pPlugin,
404                                  CPCHAR path,
405                                  CPCHAR remain,
406                                  const PDmtTree & tree)
407{
408    SYNCML_DM_RET_STATUS_T dm_stat;
409    const char * ptr;    //point to remaining stuff after *
410
411    XPL_LOG_DM_TMN_Debug(("CheckMultiNode %s:%s\n", path, remain));
412
413    ptr=remain;
414    while ( * ptr != '*' && * ptr != '\0')
415        ptr ++;
416
417    if ( *ptr == '*' )
418    {
419        DMString strPath=path;
420        strPath += DMString(remain, (int) ptr - (int)remain -1);
421
422        ptr++;
423
424        DMStringVector mapNodeNames;
425        dm_stat = tree->GetChildNodeNames(strPath.c_str(),mapNodeNames);
426        if ( dm_stat != SYNCML_DM_SUCCESS )
427            return dm_stat;
428
429        for (INT32 i=0; i<mapNodeNames.size(); i++)
430        {
431            DMString childPath;
432            childPath =strPath;
433            childPath += "/";
434            childPath += mapNodeNames[i];
435
436            dm_stat = DmCheckMultiNodeConstraint(pPlugin,childPath.c_str(),ptr,tree);
437            if ( dm_stat != SYNCML_DM_SUCCESS)
438                return dm_stat;
439        }
440    }
441    else
442    {
443        DMString strPath=path;
444        strPath += remain;
445        dm_stat=(pPlugin)->CheckConstraint(strPath.c_str(),tree);
446    }
447
448
449   return dm_stat;
450}
451