Implemented on demand/static loading of plugins (part I); ATTENTION: pluginf config...
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_backup_filelist.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_backup_filelist.c
13  * @ingroup        Persistence client library
14  * @author         Ingo Huerner
15  * @brief          Implementation of persistence client library backup filelist
16  * @see
17  */
18
19 #include "persistence_client_library_backup_filelist.h"
20 #include "persistence_client_library_handle.h"
21 #include "rbtree.h"
22
23 #include "crc32.h"
24 #include "persistence_client_library_data_organization.h"
25
26
27 #if USE_FILECACHE
28    #include <persistence_file_cache.h>
29 #endif
30
31
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <sys/sendfile.h>
37
38
39 /// structure definition for a key value item
40 typedef struct _key_value_s
41 {
42    unsigned int key;
43    char*        value;
44 }key_value_s;
45
46
47 void  key_val_rel(void *p);
48
49 void* key_val_dup(void *p);
50
51 int key_val_cmp(const void *p1, const void *p2 );
52
53
54 char* gpConfigFileMap = 0;
55 char* gpTokenArray[TOKENARRAYSIZE] = {0};
56 int gTokenCounter = 0;
57 unsigned int gConfigFileSize = 0;
58
59
60 /// the rb tree
61 static jsw_rbtree_t *gRb_tree_bl = NULL;
62
63
64 // local function prototypes
65 int need_backup_key(unsigned int key);
66
67
68 void fillFileBackupCharTokenArray()
69 {
70    unsigned int i=0;
71    int blankCount=0;
72    char* tmpPointer = gpConfigFileMap;
73
74    // set the first pointer to the start of the file
75    gpTokenArray[blankCount] = tmpPointer;
76    blankCount++;
77
78    while(i < gConfigFileSize)
79    {
80       if(   ((unsigned int)*tmpPointer < 127)
81          && ((unsigned int)*tmpPointer >= 0))
82            {
83                    if(1 != gCharLookup[(unsigned int)*tmpPointer])
84                    {
85                            *tmpPointer = 0;
86
87                            // check if we are at the end of the token array
88                            if(blankCount >= TOKENARRAYSIZE)
89                            {
90                                    break;
91                            }
92                            gpTokenArray[blankCount] = tmpPointer+1;
93                            blankCount++;
94                            gTokenCounter++;
95                    }
96            }
97       tmpPointer++;
98            i++;
99    }
100 }
101
102
103 void createAndStoreFileNames()
104 {
105    int i= 0, j =0;
106    char path[128];
107    const char* gFilePostFix                = ".pers";
108    const char* gKeyPathFormat              = "/%s/%s/%s/%s/%s%s";
109    key_value_s* item;
110
111    // creat new tree
112    gRb_tree_bl = jsw_rbnew(key_val_cmp, key_val_dup, key_val_rel);
113
114    if(gRb_tree_bl != NULL)
115    {
116
117       for(i=0; i<128; i++)
118       {
119          // assemble path
120          snprintf(path, 128, gKeyPathFormat, gpTokenArray[j+2],      // storage type
121                                              gpTokenArray[j+3],      // policy id
122                                              gpTokenArray[j+4],      // profileID
123                                              gpTokenArray[j],        // application id
124                                              gpTokenArray[j+1],      // filename
125                                              gFilePostFix);          // file postfix
126
127          // asign key and value to the rbtree item
128          item = malloc(sizeof(key_value_s));
129          if(item != NULL)
130          {
131             item->key = pclCrc32(0, (unsigned char*)path, strlen(path));
132             // we don't need the path name here, we just need to know that this key is available in the tree
133             item->value = "";
134             jsw_rbinsert(gRb_tree_bl, item);
135             free(item);
136          }
137          j+=5;
138          if(gpTokenArray[j] == NULL)
139          {
140             break;
141          }
142       }
143    }
144
145 }
146
147
148 int readBlacklistConfigFile(const char* filename)
149 {
150    int fd = 0,
151        status = 0,
152        rval = 0;
153
154    struct stat buffer;
155
156    if(filename != NULL)
157    {
158
159            memset(&buffer, 0, sizeof(buffer));
160            status = stat(filename, &buffer);
161            if(status != -1)
162            {
163                   gConfigFileSize = buffer.st_size;
164            }
165
166            fd = open(filename, O_RDONLY);
167            if (fd == -1)
168            {
169                   DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file open"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
170                   return -1;
171            }
172
173            // check for empty file
174            if(gConfigFileSize == 0)
175            {
176                   DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file size is 0:"), DLT_STRING(filename));
177                   close(fd);
178                   return -1;
179            }
180
181            // map the config file into memory
182            gpConfigFileMap = (char*)mmap(0, gConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0);
183
184            if (gpConfigFileMap == MAP_FAILED)
185            {
186                   gpConfigFileMap = 0;
187                   close(fd);
188                   DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("configReader::readConfigFile ==> Error mapping the file:"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
189
190                   return -1;
191            }
192
193            // reset the token counter
194            gTokenCounter = 0;
195
196            fillFileBackupCharTokenArray();
197
198            // create filenames and store them in the tree
199            createAndStoreFileNames();
200
201            munmap(gpConfigFileMap, gConfigFileSize);
202
203            close(fd);
204    }
205    else
206    {
207            rval = -1;
208    }
209
210    return rval;
211 }
212
213
214
215 int need_backup_key(unsigned int key)
216 {
217    int rval = 1;
218    key_value_s* item = NULL;
219    key_value_s* foundItem = NULL;
220
221    item = malloc(sizeof(key_value_s));
222    if(item != NULL && gRb_tree_bl != NULL)
223    {
224       item->key = key;
225       foundItem = (key_value_s*)jsw_rbfind(gRb_tree_bl, item);
226       if(foundItem != NULL)
227       {
228          rval = 0;
229       }
230       free(item);
231    }
232    else
233    {
234       if(item!=NULL)
235              free(item);
236
237       rval = -1;
238       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("need_backup_key ==> item or gRb_tree_bl is NULL"));
239    }
240
241    return rval;
242 }
243
244
245 /// compare function for tree key_value_s item
246 int key_val_cmp(const void *p1, const void *p2 )
247 {
248    int rval = -1;
249    key_value_s* first;
250    key_value_s* second;
251
252    first  = (key_value_s*)p1;
253    second = (key_value_s*)p2;
254
255    if(second->key == first->key)
256    {
257       rval = 0;
258    }
259    else if(second->key < first->key)
260    {
261       rval = -1;
262    }
263    else
264    {
265       rval = 1;
266    }
267
268    return rval;
269  }
270
271 /// duplicate function for key_value_s item
272 void* key_val_dup(void *p)
273 {
274    int value_size = 0;
275    key_value_s* src = NULL;
276    key_value_s* dst = NULL;
277
278    src = (key_value_s*)p;
279    value_size = strlen(src->value)+1;
280
281    // allocate memory for node
282    dst = malloc(sizeof(key_value_s));
283    if(dst != NULL)
284    {
285       // duplicate hash key
286      dst->key = src->key;
287
288      // duplicate value
289      dst->value = malloc(value_size);
290      if(dst->value != NULL)
291         strncpy(dst->value, src->value, value_size);
292    }
293
294
295    return dst;
296 }
297
298 /// release function for key_value_s item
299 void  key_val_rel(void *p )
300 {
301    key_value_s* rel = NULL;
302    rel = (key_value_s*)p;
303
304    if(rel->value != NULL)
305       free(rel->value);
306
307    if(rel != NULL)
308       free(rel);
309 }
310
311
312 int pclBackupDoFileCopy(int srcFd, int dstFd)
313 {
314    struct stat buf;
315    memset(&buf, 0, sizeof(buf));
316
317    fstat(srcFd, &buf);
318    return sendfile(dstFd, srcFd, 0, buf.st_size);
319 }
320
321
322 int pclCreateFile(const char* path)
323 {
324    const char* delimiters = "/\n";   // search for blank and end of line
325    char* tokenArray[24];
326    char thePath[DbPathMaxLen] = {0};
327    int numTokens = 0, i = 0, validPath = 1;
328    int handle = -1;
329
330    strncpy(thePath, path, DbPathMaxLen);
331
332    tokenArray[numTokens++] = strtok(thePath, delimiters);
333    while(tokenArray[numTokens-1] != NULL )
334    {
335      tokenArray[numTokens] = strtok(NULL, delimiters);
336      if(tokenArray[numTokens] != NULL)
337      {
338         numTokens++;
339         if(numTokens >= 24)
340         {
341            validPath = 0;
342            break;
343         }
344      }
345      else
346      {
347         break;
348      }
349    }
350
351    if(validPath == 1)
352    {
353       char createPath[DbPathMaxLen] = {0};
354       snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
355       for(i=1; i<numTokens-1; i++)
356       {
357          // create folders
358          strncat(createPath, "/", DbPathMaxLen-1);
359          strncat(createPath, tokenArray[i], DbPathMaxLen-1);
360          mkdir(createPath, 0744);
361       }
362       // finally create the file
363       strncat(createPath, "/", DbPathMaxLen-1);
364       strncat(createPath, tokenArray[i], DbPathMaxLen-1);
365 #if USE_FILECACHE
366       handle = pfcOpenFile(createPath, CreateFile);
367 #else
368       handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
369 #endif
370    }
371    else
372    {
373       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
374    }
375
376    return handle;
377 }
378
379
380 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
381 {
382    int handle = 0, readSize = 0;
383    int backupAvail = 0, csumAvail = 0;
384    int fdCsum = 0, fdBackup = 0;
385
386    char origCsumBuf[ChecksumBufSize] = {0};
387    char backCsumBuf[ChecksumBufSize] = {0};
388    char csumBuf[ChecksumBufSize]     = {0};
389
390    // check if we have a backup and checksum file
391    backupAvail = access(backupPath, F_OK);
392    csumAvail   = access(csumPath, F_OK);
393
394    // *************************************************
395    // there is a backup file and a checksum
396    // *************************************************
397    if( (backupAvail == 0) && (csumAvail == 0) )
398    {
399       DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is a backup file AND a checksum"));
400       // calculate checksum form backup file
401       fdBackup = open(backupPath,  O_RDONLY);
402       if(fdBackup != -1)
403       {
404          pclCalcCrc32Csum(fdBackup, backCsumBuf);
405
406          fdCsum = open(csumPath,  O_RDONLY);
407          if(fdCsum != -1)
408          {
409             readSize = read(fdCsum, csumBuf, ChecksumBufSize);
410             if(readSize > 0)
411             {
412                if(strcmp(csumBuf, backCsumBuf)  == 0)
413                {
414                   // checksum matches ==> replace with original file
415                   handle = pclRecoverFromBackup(fdBackup, origPath);
416                }
417                else
418                {
419                   // checksum does not match, check checksum with original file
420                   handle = open(origPath, openFlags);
421                   if(handle != -1)
422                   {
423                      pclCalcCrc32Csum(handle, origCsumBuf);
424                      if(strcmp(csumBuf, origCsumBuf)  != 0)
425                      {
426                         close(handle);
427                         handle = -1;  // error: file corrupt
428                      }
429                      // else case: checksum matches ==> keep original file ==> nothing to do
430
431                   }
432                   else
433                   {
434                      close(handle);
435                      handle = -1;     // error: file corrupt
436                   }
437                }
438             }
439             close(fdCsum);
440          }
441          else
442          {
443             close(fdCsum);
444             handle = -1;     // error: file corrupt
445          }
446       }
447       else
448       {
449          handle = -1;
450       }
451       close(fdBackup);
452    }
453    // *************************************************
454    // there is ONLY a checksum file
455    // *************************************************
456    else if(csumAvail == 0)
457    {
458       DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
459
460       fdCsum = open(csumPath,  O_RDONLY);
461       if(fdCsum != -1)
462       {
463          readSize = read(fdCsum, csumBuf, ChecksumBufSize);
464          if(readSize <= 0)
465          {
466             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
467          }
468          close(fdCsum);
469
470          // calculate the checksum form the original file to see if it matches
471          handle = open(origPath, openFlags);
472          if(handle != -1)
473          {
474             pclCalcCrc32Csum(handle, origCsumBuf);
475
476             if(strcmp(csumBuf, origCsumBuf)  != 0)
477             {
478                 close(handle);
479                 handle = -1;  // checksum does NOT match ==> error: file corrupt
480             }
481             // else case: checksum matches ==> keep original file ==> nothing to do
482          }
483          else
484          {
485             close(handle);
486             handle = -1;      // error: file corrupt
487          }
488       }
489       else
490       {
491          close(fdCsum);
492          handle = -1;         // error: file corrupt
493       }
494    }
495    // *************************************************
496    // there is ONLY a backup file
497    // *************************************************
498    else if(backupAvail == 0)
499    {
500       DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
501
502       // calculate checksum form backup file
503       fdBackup = open(backupPath,  O_RDONLY);
504       if(fdBackup != -1)
505       {
506          pclCalcCrc32Csum(fdBackup, backCsumBuf);
507          close(fdBackup);
508
509          // calculate the checksum form the original file to see if it matches
510          handle = open(origPath, openFlags);
511          if(handle != -1)
512          {
513             pclCalcCrc32Csum(handle, origCsumBuf);
514
515             if(strcmp(backCsumBuf, origCsumBuf)  != 0)
516             {
517                close(handle);
518                handle = -1;   // checksum does NOT match ==> error: file corrupt
519             }
520             // else case: checksum matches ==> keep original file ==> nothing to do
521
522          }
523          else
524          {
525             close(handle);
526             handle = -1;      // error: file corrupt
527          }
528       }
529       else
530       {
531          close(fdBackup);
532          handle = -1;         // error: file corrupt
533       }
534    }
535    // for else case: nothing to do
536
537
538    // if we are in an inconsistent state: delete file, backup and checksum
539    if(handle == -1)
540    {
541       remove(origPath);
542       remove(backupPath);
543       remove(csumPath);
544    }
545
546    return handle;
547 }
548
549
550
551 int pclRecoverFromBackup(int backupFd, const char* original)
552 {
553    int handle = 0;
554
555    handle = open(original, O_TRUNC | O_RDWR);
556    if(handle != -1)
557    {
558       // copy data from one file to another
559       if(pclBackupDoFileCopy(backupFd, handle) == -1)
560       {
561          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
562       }
563    }
564
565    return handle;
566 }
567
568
569
570 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
571 {
572    int dstFd = 0, csfd = 0;
573    int readSize = -1;
574
575    if(access(dstPath, F_OK) != 0)
576    {
577       int handle = -1;
578       char pathToCreate[DbPathMaxLen] = {0};
579       strncpy(pathToCreate, dstPath, DbPathMaxLen);
580
581       handle = pclCreateFile(pathToCreate);
582       close(handle); // don't need the open file
583    }
584
585    // create checksum file and and write checksum
586    csfd = open(csumPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
587    if(csfd != -1)
588    {
589       int csumSize = strlen(csumBuf);
590       if(write(csfd, csumBuf, csumSize) != csumSize)
591       {
592          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
593       }
594       close(csfd);
595    }
596    else
597    {
598       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
599    }
600
601    // create backup file, user and group has read/write permission, others have read permission
602    dstFd = open(dstPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
603    if(dstFd != -1)
604    {
605       off_t curPos = 0;
606       // remember the current position
607       curPos = lseek(srcfd, 0, SEEK_CUR);
608
609       // copy data from one file to another
610       if((readSize = pclBackupDoFileCopy(srcfd, dstFd)) == -1)
611       {
612          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
613       }
614
615       if(close(dstFd) == -1)
616       {
617          DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
618       }
619
620       // set back to the position
621       lseek(srcfd, curPos, SEEK_SET);
622    }
623    else
624    {
625       DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
626                                           DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
627    }
628
629    return readSize;
630 }
631
632
633
634 int pclCalcCrc32Csum(int fd, char crc32sum[])
635 {
636    int rval = 1;
637
638    if(crc32sum != 0)
639    {
640       char* buf;
641       struct stat statBuf;
642
643       fstat(fd, &statBuf);
644       buf = malloc((unsigned int)statBuf.st_size);
645
646       if(buf != 0)
647       {
648          off_t curPos = 0;
649          // remember the current position
650          curPos = lseek(fd, 0, SEEK_CUR);
651
652          if(curPos != 0)
653          {
654             // set to beginning of the file
655             lseek(fd, 0, SEEK_SET);
656          }
657
658          while((rval = read(fd, buf, statBuf.st_size)) > 0)
659          {
660             unsigned int crc = 0;
661             crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
662             snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
663          }
664
665          // set back to the position
666          lseek(fd, curPos, SEEK_SET);
667
668          free(buf);
669       }
670       else
671       {
672         rval = -1;
673       }
674    }
675    return rval;
676 }
677
678
679
680 int pclBackupNeeded(const char* path)
681 {
682    return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
683 }
684
685
686
687 int pclGetPosixPermission(PersistencePermission_e permission)
688 {
689    int posixPerm = -1;
690
691    switch( (int)permission)
692    {
693    case PersistencePermission_ReadWrite:
694       posixPerm = O_RDWR;
695       break;
696    case PersistencePermission_ReadOnly:
697       posixPerm = O_RDONLY;
698       break;
699    case PersistencePermission_WriteOnly:
700       posixPerm = O_WRONLY;
701       break;
702    default:
703       posixPerm = O_RDONLY;
704       break;
705    }
706
707    return posixPerm;
708 }
709
710
711