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