Added use of default data for files; added test data that can be used by PAS installa...
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_db_access.c
1 /******************************************************************************
2  * Project         Persistency
3  * (c) copyright   2012
4  * Company         XS Embedded GmbH
5  *****************************************************************************/
6 /******************************************************************************
7  * This Source Code Form is subject to the terms of the
8  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed
9  * with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 ******************************************************************************/
11  /**
12  * @file           persistence_client_library_data_access.c
13  * @ingroup        Persistence client library
14  * @author         Ingo Huerner
15  * @brief          Implementation of persistence database access
16  *                 Library provides an API to access persistent data
17  * @see            
18  */
19
20 #include "persistence_client_library_db_access.h"
21 #include "persistence_client_library_custom_loader.h"
22 #include "persistence_client_library_dbus_service.h"
23 #include "persistence_client_library_prct_access.h"
24
25 #include <persComErrors.h>
26 #include <persComDataOrg.h>
27 #include <persComDbAccess.h>
28
29 #include <dbus/dbus.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34
35
36
37 /// btree array
38 static int gHandlesDB[DbTableSize][PersistencePolicy_LastEntry];
39 static int gHandlesDBCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} };
40
41
42 // function prototype
43 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, unsigned int reason);
44
45
46 char* pers_get_raw_key(char *key)
47 {
48    char *temp = NULL;
49    char *rawKey = key;
50
51    temp = strrchr(key, (int)'/');
52    
53    if (NULL != temp)
54    {
55           rawKey = temp + 1;
56    }
57
58    return rawKey;
59 }
60
61
62 int pers_db_open_default(const char* dbPath, PersDefaultType_e DefaultType)
63 {
64    int ret = 0;
65    char path[DbPathMaxLen] = {0};
66
67    if (PersDefaultType_Configurable == DefaultType)
68    {
69       snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalConfigurableDefault);
70    }
71    else if (PersDefaultType_Factory== DefaultType)
72    {
73       snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalFactoryDefault);
74    }
75    else
76    {
77       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_db_open_default ==> unknown DefaultType"));
78       ret = EPERS_COMMON;
79    }
80
81    if (EPERS_COMMON != ret)
82    {
83       ret = persComDbOpen(path, 0);
84       if (ret < 0)
85       {
86          ret = EPERS_COMMON;
87          DLT_LOG(gPclDLTContext, DLT_LOG_WARN,
88                               DLT_STRING("pers_db_open_default() -> persComDbOpen() -> problem open db: "),
89                               DLT_STRING(path),
90                               DLT_STRING(" Code: "),
91                               DLT_INT(ret));
92       }
93    }
94
95    return ret;
96 }
97
98
99 int pers_get_defaults(char* dbPath, char* key, unsigned char* buffer, unsigned int buffer_size, PersGetDefault_e job)
100 {
101    PersDefaultType_e i = PersDefaultType_Configurable;
102    int handleDefaultDB = -1;
103    int read_size = EPERS_NOKEY;
104
105    key = pers_get_raw_key(key); /* We need only the raw key without a prefixed '/node/' or '/user/1/seat/0' etc... */
106
107    for(i=0; i<PersDefaultType_LastEntry; i++)
108    {
109       handleDefaultDB = pers_db_open_default(dbPath, i);
110       if(handleDefaultDB >= 0)
111       {
112          if (PersGetDefault_Data == job)
113          {
114          }
115          else if (PersGetDefault_Size == job)
116          {
117             read_size = persComDbGetKeySize(handleDefaultDB, key);
118          }
119          else
120          {
121             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_get_defaults ==> unknown job"));
122             break;
123          }
124
125          if (0 > persComDbClose(handleDefaultDB))
126          {
127             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_get_defaults ==> persComDbClose returned with error"));
128          }
129
130          if(read_size < 0) // check read_size
131          {
132             if (PersDefaultType_Configurable == i)
133             {
134                DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Key '"),
135                                                   DLT_STRING(key),
136                                                   DLT_STRING("' not found in "),
137                                                   DLT_STRING(dbPath),
138                                                   DLT_STRING(gLocalConfigurableDefault));
139             }
140             else if (PersDefaultType_Factory == i)
141             {
142                DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Key '"),
143                                                   DLT_STRING(key),
144                                                   DLT_STRING("' not found in "),
145                                                   DLT_STRING(dbPath),
146                                                   DLT_STRING(gLocalFactoryDefault));
147             }
148             else
149             {
150                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_get_defaults ==> unknown PersDefaultType: "),
151                                                    DLT_INT(i));
152             }
153
154             if(PERS_COM_ERR_NOT_FOUND == read_size)
155             {
156                read_size = EPERS_NOKEY;
157             }
158          }
159          else
160          {
161             break;
162          }
163       }
164    }
165
166    return read_size;
167
168 }
169
170
171 int database_get(PersistenceInfo_s* info, const char* dbPath)
172 {
173    int arrayIdx = 0;
174    int handleDB = -1;
175
176    // create array index: index is a combination of resource config table type and group
177    arrayIdx = info->configKey.storage + info->context.ldbid ;
178
179    //if(arrayIdx <= DbTableSize)
180    if(arrayIdx < DbTableSize)
181    {
182       if(gHandlesDBCreated[arrayIdx][info->configKey.policy] == 0)
183       {
184
185          char path[DbPathMaxLen] = {0};
186
187          if(PersistencePolicy_wt == info->configKey.policy)
188          {
189             snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalWt);
190          }
191          else if(PersistencePolicy_wc == info->configKey.policy)
192          {
193             snprintf(path, DbPathMaxLen, "%s%s", dbPath, gLocalCached);
194          }
195          else
196          {
197             handleDB = -2;
198          }
199
200          if (handleDB == -1)
201          {
202             handleDB = persComDbOpen(path, 0x01);
203             if(handleDB >= 0)
204             {
205                gHandlesDB[arrayIdx][info->configKey.policy] = handleDB ;
206                gHandlesDBCreated[arrayIdx][info->configKey.policy] = 1;
207             }
208             else
209             {
210                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_get ==> persComDbOpen() failed"));
211             }
212          }
213          else
214          {
215             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_get ==> wrong policy! Cannot extend dbPath wit database."));
216          }
217       }
218       else
219       {
220          handleDB = gHandlesDB[arrayIdx][info->configKey.policy];
221       }
222    }
223    else
224    {
225       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_get ==> invalid storage type"), DLT_STRING(dbPath));
226    }
227
228
229
230    return handleDB;
231 }
232
233
234 void database_close(PersistenceInfo_s* info)
235 {
236    int arrayIdx = info->configKey.storage + info->context.ldbid;
237
238    if(info->configKey.storage <= PersistenceStorage_shared )
239    {
240       int iErrorCode = persComDbClose(gHandlesDB[arrayIdx][info->configKey.policy]) ;
241       if (iErrorCode < 0)
242       {
243          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close ==> persComDbClose() failed"));
244       }
245       else
246       {
247         gHandlesDBCreated[arrayIdx][info->configKey.policy] = 0;
248       }
249    }
250    else
251    {
252       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close ==> invalid storage type"), DLT_INT(info->context.ldbid ));
253    }
254 }
255
256 void database_close_all()
257 {
258    int i = 0;
259
260    for(i=0; i<DbTableSize; i++)
261    {
262       // close write cached database
263       if(gHandlesDBCreated[i][PersistencePolicy_wc] == 1)
264       {
265          int iErrorCode = persComDbClose(gHandlesDB[i][PersistencePolicy_wc]);
266          if (iErrorCode < 0)
267          {
268             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close_all => failed to close db => persComDbClose"));
269          }
270          else
271          {
272              gHandlesDBCreated[i][PersistencePolicy_wc] = 0;
273          }
274       }
275
276       // close write through database
277       if(gHandlesDBCreated[i][PersistencePolicy_wt] == 1)
278       {
279          int iErrorCode = persComDbClose(gHandlesDB[i][PersistencePolicy_wt]);
280          if (iErrorCode < 0)
281          {
282             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("database_close_all => failed to close db => persComDbClose"));
283          }
284          else
285          {
286             gHandlesDBCreated[i][PersistencePolicy_wt] = 0;
287          }
288       }
289    }
290 }
291
292
293
294 int persistence_get_data(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
295 {
296    int read_size = -1;
297    int ret_defaults = -1;
298
299    if(   PersistenceStorage_shared == info->configKey.storage
300       || PersistenceStorage_local == info->configKey.storage)
301    {
302       int handleDB = database_get(info, dbPath);
303       if(handleDB >= 0)
304       {
305          read_size = persComDbReadKey(handleDB, key, (char*)buffer, buffer_size) ;
306          if(read_size < 0)
307          {
308             read_size = pers_get_defaults(dbPath, key, buffer, buffer_size, PersGetDefault_Data); /* 0 ==> Get data */
309          }
310       }
311    }
312    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
313    {
314       int idx =  custom_client_name_to_id(dbPath, 1);
315       char workaroundPath[128];  // workaround, because /sys/ can not be accessed on host!!!!
316       snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath  );
317
318       if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_data != NULL) )
319       {
320          char pathKeyString[128] = {0};
321          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
322          {
323             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
324          }
325          else
326          {
327             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
328          }
329          read_size = gPersCustomFuncs[idx].custom_plugin_get_data(pathKeyString, (char*)buffer, buffer_size);
330       }
331       else
332       {
333          read_size = EPERS_NOPLUGINFUNCT;
334       }
335
336       if (1 > read_size)
337       {
338          info->configKey.policy = PersistencePolicy_wc;                 /* Set the policy */
339          info->configKey.type   = PersistenceResourceType_key;  /* Set the type */
340          (void)get_db_path_and_key(info, key, NULL, dbPath);
341          DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Custom Key not available. Try to get default keys from:"),
342                                             DLT_STRING(dbPath),
343                                             DLT_STRING(key));
344          ret_defaults = pers_get_defaults(dbPath, key, buffer, buffer_size, PersGetDefault_Data);
345          if (0 < ret_defaults)
346          {
347                  read_size = ret_defaults;
348          }
349       }
350    }
351    return read_size;
352 }
353
354
355
356 int persistence_set_data(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char* buffer, unsigned int buffer_size)
357 {
358    int write_size = -1;
359
360    if(   PersistenceStorage_local == info->configKey.storage
361       || PersistenceStorage_shared == info->configKey.storage )
362    {
363       int handleDB = -1 ;
364
365
366       handleDB = database_get(info, dbPath);
367       if(handleDB >= 0)
368       {
369          write_size = persComDbWriteKey(handleDB, key, (char*)buffer, buffer_size) ;
370          if(write_size < 0)
371          {
372             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> persComDbWriteKey() failure"));
373          }
374
375          if(PersistenceStorage_shared == info->configKey.storage)
376          {
377             int rval = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
378             if(rval <= 0)
379             {
380                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> failed to send notification signal"));
381                write_size = rval;
382             }
383          }
384
385       }
386       else
387       {
388          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
389          write_size = EPERS_NOPRCTABLE;
390       }
391    }
392    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
393    {
394       int idx = custom_client_name_to_id(dbPath, 1);
395       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_set_data != NULL) )
396       {
397          char pathKeyString[128] = {0};
398          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
399          {
400             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
401          }
402          else
403          {
404             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
405          }
406          write_size = gPersCustomFuncs[idx].custom_plugin_set_data(pathKeyString, (char*)buffer, buffer_size);
407
408          if (write_size == buffer_size) /* Check return value and send notification if OK */
409          {
410             int rval = pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_changed);
411             if(rval <= 0)
412             {
413                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_set_data ==> failed to send notification signal"));
414                write_size = rval;
415             }
416          }
417       }
418       else
419       {
420          write_size = EPERS_NOPLUGINFUNCT;
421       }
422    }
423    return write_size;
424 }
425
426
427
428 int persistence_get_data_size(char* dbPath, char* key, PersistenceInfo_s* info)
429 {
430    int read_size = -1;
431    int ret_defaults = -1;
432
433    if(   PersistenceStorage_shared == info->configKey.storage
434       || PersistenceStorage_local == info->configKey.storage)
435    {
436       int handleDB = database_get(info, dbPath);
437       if(handleDB >= 0)
438       {
439          read_size = persComDbGetKeySize(handleDB, key);
440          if(read_size < 0)
441          {
442             read_size = pers_get_defaults(dbPath, key, NULL, 0, PersGetDefault_Size);
443          }
444       }
445    }
446    else if(PersistenceStorage_custom == info->configKey.storage)   // custom storage implementation via custom library
447    {
448       int idx = custom_client_name_to_id(dbPath, 1);
449       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_get_size != NULL) )
450       {
451          char pathKeyString[128] = {0};
452          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
453          {
454             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
455          }
456          else
457          {
458             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
459          }
460          read_size = gPersCustomFuncs[idx].custom_plugin_get_size(pathKeyString);
461       }
462       else
463       {
464          read_size = EPERS_NOPLUGINFUNCT;
465       }
466
467       if (1 > read_size)
468       {
469          info->configKey.policy = PersistencePolicy_wc;                 /* Set the policy */
470          info->configKey.type   = PersistenceResourceType_key;  /* Set the type */
471          (void)get_db_path_and_key(info, key, NULL, dbPath);
472          DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Custom Key not available. Try to get default keys from:"),
473                                             DLT_STRING(dbPath),
474                                             DLT_STRING(key));
475          ret_defaults = pers_get_defaults(dbPath, key, NULL, 0, PersGetDefault_Size);
476          if (0 < ret_defaults)
477          {
478                  read_size = ret_defaults;
479          }
480       }
481    }
482    return read_size;
483 }
484
485
486
487 int persistence_delete_data(char* dbPath, char* key, PersistenceInfo_s* info)
488 {
489    int ret = 0;
490    if(PersistenceStorage_custom != info->configKey.storage)
491    {
492       int handleDB = database_get(info, dbPath);
493       if(handleDB >= 0)
494       {
495          ret = persComDbDeleteKey(handleDB, key) ;
496          if(ret < 0)
497          {
498             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_delete_data => persComDbDeleteKey failed: "), DLT_STRING(key));
499             if(PERS_COM_ERR_NOT_FOUND == ret)
500             {
501                 ret = EPERS_NOKEY ;
502             }
503             else
504             {
505                 ret = EPERS_DB_ERROR_INTERNAL ;
506             }
507          }
508
509          if(PersistenceStorage_shared == info->configKey.storage)
510          {
511             pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
512          }
513       }
514       else
515       {
516          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_delete_data ==> no resource config table"), DLT_STRING(dbPath), DLT_STRING(key));
517          ret = EPERS_NOPRCTABLE;
518       }
519    }
520    else   // custom storage implementation via custom library
521    {
522       int idx = custom_client_name_to_id(dbPath, 1);
523       if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_delete_data != NULL) )
524       {
525          char pathKeyString[128] = {0};
526          if(info->configKey.customID[0] == '\0')   // if we have not a customID we use the key
527          {
528             snprintf(pathKeyString, 128, "0x%08X/%s/%s", info->context.ldbid, info->configKey.custom_name, key);
529          }
530          else
531          {
532             snprintf(pathKeyString, 128, "0x%08X/%s", info->context.ldbid, info->configKey.customID);
533          }
534          ret = gPersCustomFuncs[idx].custom_plugin_delete_data(pathKeyString);
535
536          if(0 <= ret) /* Check return value and send notification if OK */
537          {
538             pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted);
539          }
540       }
541       else
542       {
543          ret = EPERS_NOPLUGINFUNCT;
544       }
545    }
546    return ret;
547 }
548
549
550 int persistence_notify_on_change(char* key, unsigned int ldbid, unsigned int user_no, unsigned int seat_no,
551                                  pclChangeNotifyCallback_t callback, PersNotifyRegPolicy_e regPolicy)
552 {
553    int rval = 0;
554
555    if(regPolicy < Notify_lastEntry)
556    {
557       snprintf(gNotifykey, DbKeyMaxLen, "%s", key);
558       gNotifyLdbid  = ldbid;     // to do: pass correct ==> JUST TESTING!!!!
559       gNotifyUserNo = user_no;
560       gNotifySeatNo = seat_no;
561       gNotifyReason = regPolicy;
562
563       if(regPolicy == Notify_register)
564       {
565          // assign callback
566          gChangeNotifyCallback = callback;
567       }
568       else if(regPolicy == Notify_unregister)
569       {
570          // remove callback
571          gChangeNotifyCallback = NULL;
572       }
573
574       if(-1 == deliverToMainloop(CMD_REG_NOTIFY_SIGNAL, 0, 0))
575       {
576          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("persistence_notify_on_change => failed to write to pipe"), DLT_INT(errno));
577          rval = -1;
578       }
579    }
580    else
581    {
582       rval = -1;
583    }
584
585    return rval;
586 }
587
588
589
590
591
592
593 int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason)
594 {
595    int rval = 1;
596    if(reason < pclNotifyStatus_lastEntry)
597    {
598       snprintf(gNotifykey,  DbKeyMaxLen,       "%s", key);
599
600       gNotifyLdbid  = context->ldbid;     // to do: pass correct ==> JUST TESTING!!!!
601       gNotifyUserNo = context->user_no;
602       gNotifySeatNo = context->seat_no;
603       gNotifyReason = reason;
604
605       if(-1 == deliverToMainloop(CMD_SEND_NOTIFY_SIGNAL, 0,0) )
606       {
607          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pers_send_Notification_Signal => failed to write to pipe"), DLT_INT(errno));
608          rval = EPERS_NOTIFY_SIG;
609       }
610    }
611    else
612    {
613       rval = EPERS_NOTIFY_SIG;
614    }
615
616    return rval;
617 }
618
619
620 void pers_rct_close_all()
621 {
622    int i = 0;
623
624    // close open persistence resource configuration table
625    for(i=0; i< PrctDbTableSize; i++)
626    {
627         if(gResource_table[i] != 0)
628         {
629                         if(persComRctClose(i) != 0)
630                         {
631                                 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("process_prepare_shutdown => failed to close db => index:"), DLT_INT(i));
632                         }
633
634                         gResource_table[i] = 0;
635         }
636    }
637 }
638