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