Removed compiler warnings
[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 = (char*)path;
337    int numTokens = 0, i = 0, validPath = 1;
338    int handle = 0;
339
340    tokenArray[numTokens++] = strtok(thePath, delimiters);
341    while(tokenArray[numTokens-1] != NULL )
342    {
343      tokenArray[numTokens] = strtok(NULL, delimiters);
344      if(tokenArray[numTokens] != NULL)
345      {
346         numTokens++;
347         if(numTokens >= 24)
348         {
349            validPath = 0;
350            break;
351         }
352      }
353      else
354      {
355         break;
356      }
357    }
358
359    if(validPath == 1)
360    {
361       char createPath[DbPathMaxLen] = {0};
362       snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
363       for(i=1; i<numTokens-1; i++)
364       {
365          // create folders
366          strncat(createPath, "/", DbPathMaxLen-1);
367          strncat(createPath, tokenArray[i], DbPathMaxLen-1);
368          mkdir(createPath, 0744);
369       }
370       // finally create the file
371       strncat(createPath, "/", DbPathMaxLen-1);
372       strncat(createPath, tokenArray[i], DbPathMaxLen-1);
373       handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
374       if(handle != -1)
375       {
376          if(handle < MaxPersHandle)
377          {
378             __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
379          }
380          else
381          {
382             close(handle);
383             handle = EPERS_MAXHANDLE;
384          }
385       }
386    }
387    else
388    {
389       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
390    }
391
392    return handle;
393 }
394
395
396 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
397 {
398    int handle = 0, readSize = 0;
399    int backupAvail = 0, csumAvail = 0;
400    int fdCsum = 0, fdBackup = 0;
401
402    char origCsumBuf[ChecksumBufSize] = {0};
403    char backCsumBuf[ChecksumBufSize] = {0};
404    char csumBuf[ChecksumBufSize]     = {0};
405
406    // check if we have a backup and checksum file
407    backupAvail = access(backupPath, F_OK);
408    csumAvail   = access(csumPath, F_OK);
409
410    // *************************************************
411    // there is a backup file and a checksum
412    // *************************************************
413    if( (backupAvail == 0) && (csumAvail == 0) )
414    {
415       DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is a backup file AND a checksum"));
416       // calculate checksum form backup file
417       fdBackup = open(backupPath,  O_RDONLY);
418       if(fdBackup != -1)
419       {
420          pclCalcCrc32Csum(fdBackup, backCsumBuf);
421
422          fdCsum = open(csumPath,  O_RDONLY);
423          if(fdCsum != -1)
424          {
425             readSize = read(fdCsum, csumBuf, ChecksumBufSize);
426             if(readSize > 0)
427             {
428                if(strcmp(csumBuf, backCsumBuf)  == 0)
429                {
430                   // checksum matches ==> replace with original file
431                   handle = pclRecoverFromBackup(fdBackup, origPath);
432                }
433                else
434                {
435                   // checksum does not match, check checksum with original file
436                   handle = open(origPath, openFlags);
437                   if(handle != -1)
438                   {
439                      pclCalcCrc32Csum(handle, origCsumBuf);
440                      if(strcmp(csumBuf, origCsumBuf)  != 0)
441                      {
442                         close(handle);
443                         handle = -1;  // error: file corrupt
444                      }
445                      // else case: checksum matches ==> keep original file ==> nothing to do
446
447                   }
448                   else
449                   {
450                      close(handle);
451                      handle = -1;     // error: file corrupt
452                   }
453                }
454             }
455             close(fdCsum);
456          }
457          else
458          {
459             close(fdCsum);
460             handle = -1;     // error: file corrupt
461          }
462       }
463       else
464       {
465          handle = -1;
466       }
467       close(fdBackup);
468    }
469    // *************************************************
470    // there is ONLY a checksum file
471    // *************************************************
472    else if(csumAvail == 0)
473    {
474       DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
475
476       fdCsum = open(csumPath,  O_RDONLY);
477       if(fdCsum != -1)
478       {
479          readSize = read(fdCsum, csumBuf, ChecksumBufSize);
480          if(readSize <= 0)
481          {
482             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
483          }
484          close(fdCsum);
485
486          // calculate the checksum form the original file to see if it matches
487          handle = open(origPath, openFlags);
488          if(handle != -1)
489          {
490             pclCalcCrc32Csum(handle, origCsumBuf);
491
492             if(strcmp(csumBuf, origCsumBuf)  != 0)
493             {
494                 close(handle);
495                 handle = -1;  // checksum does NOT match ==> error: file corrupt
496             }
497             // else case: checksum matches ==> keep original file ==> nothing to do
498          }
499          else
500          {
501             close(handle);
502             handle = -1;      // error: file corrupt
503          }
504       }
505       else
506       {
507          close(fdCsum);
508          handle = -1;         // error: file corrupt
509       }
510    }
511    // *************************************************
512    // there is ONLY a backup file
513    // *************************************************
514    else if(backupAvail == 0)
515    {
516       DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
517
518       // calculate checksum form backup file
519       fdBackup = open(backupPath,  O_RDONLY);
520       if(fdBackup != -1)
521       {
522          pclCalcCrc32Csum(fdBackup, backCsumBuf);
523          close(fdBackup);
524
525          // calculate the checksum form the original file to see if it matches
526          handle = open(origPath, openFlags);
527          if(handle != -1)
528          {
529             pclCalcCrc32Csum(handle, origCsumBuf);
530
531             if(strcmp(backCsumBuf, origCsumBuf)  != 0)
532             {
533                close(handle);
534                handle = -1;   // checksum does NOT match ==> error: file corrupt
535             }
536             // else case: checksum matches ==> keep original file ==> nothing to do
537
538          }
539          else
540          {
541             close(handle);
542             handle = -1;      // error: file corrupt
543          }
544       }
545       else
546       {
547          close(fdBackup);
548          handle = -1;         // error: file corrupt
549       }
550    }
551    // for else case: nothing to do
552
553
554    // if we are in an inconsistent state: delete file, backup and checksum
555    if(handle == -1)
556    {
557       remove(origPath);
558       remove(backupPath);
559       remove(csumPath);
560    }
561
562    return handle;
563 }
564
565
566
567 int pclRecoverFromBackup(int backupFd, const char* original)
568 {
569    int handle = 0;
570
571    handle = open(original, O_TRUNC | O_RDWR);
572    if(handle != -1)
573    {
574       // copy data from one file to another
575       if((handle = pclBackupDoFileCopy(backupFd, handle)) == -1)
576       {
577          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
578       }
579    }
580
581    return handle;
582 }
583
584
585
586 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
587 {
588    int dstFd = 0, csfd = 0;
589    int readSize = -1;
590
591    if(access(dstPath, F_OK) != 0)
592    {
593       char pathToCreate[DbPathMaxLen] = {0};
594       strncpy(pathToCreate, dstPath, DbPathMaxLen);
595       pclCreateFileAndPath(pathToCreate);
596    }
597
598    // create checksum file and and write checksum
599    csfd = open(csumPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
600    if(csfd != -1)
601    {
602       int csumSize = strlen(csumBuf);
603       if(write(csfd, csumBuf, csumSize) != csumSize)
604       {
605          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
606       }
607       close(csfd);
608    }
609    else
610    {
611       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
612    }
613
614    // create backup file, user and group has read/write permission, others have read permission
615    dstFd = open(dstPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
616    if(dstFd != -1)
617    {
618       off_t curPos = 0;
619       // remember the current position
620       curPos = lseek(srcfd, 0, SEEK_CUR);
621
622       // copy data from one file to another
623       if((readSize = pclBackupDoFileCopy(srcfd, dstFd)) == -1)
624       {
625          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
626       }
627
628       if(close(dstFd) == -1)
629       {
630          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
631       }
632
633       // set back to the position
634       lseek(srcfd, curPos, SEEK_SET);
635    }
636    else
637    {
638       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
639                                           DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
640    }
641
642    return readSize;
643 }
644
645
646
647 int pclCalcCrc32Csum(int fd, char crc32sum[])
648 {
649    int rval = 1;
650
651    if(crc32sum != 0)
652    {
653       char* buf;
654       struct stat statBuf;
655
656       fstat(fd, &statBuf);
657       buf = malloc((unsigned int)statBuf.st_size);
658
659       if(buf != 0)
660       {
661          off_t curPos = 0;
662          // remember the current position
663          curPos = lseek(fd, 0, SEEK_CUR);
664
665          if(curPos != 0)
666          {
667             // set to beginning of the file
668             lseek(fd, 0, SEEK_SET);
669          }
670
671          while((rval = read(fd, buf, statBuf.st_size)) > 0)
672          {
673             unsigned int crc = 0;
674             crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
675             snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
676          }
677
678          // set back to the position
679          lseek(fd, curPos, SEEK_SET);
680
681          free(buf);
682       }
683    }
684    return rval;
685 }
686
687
688
689 int pclBackupNeeded(const char* path)
690 {
691    return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
692 }
693
694
695
696 int pclCreateFileAndPath(const char* path)
697 {
698    const char* delimiters = "/\n";   // search for blank and end of line
699    char* tokenArray[24];
700    char* thePath = (char*)path;
701    char createPath[DbPathMaxLen] = {0};
702    int numTokens = 0, i = 0, validPath = 1;
703    int rval = -1;
704
705    tokenArray[numTokens++] = strtok(thePath, delimiters);
706    while(tokenArray[numTokens-1] != NULL )
707    {
708      tokenArray[numTokens] = strtok(NULL, delimiters);
709      if(tokenArray[numTokens] != NULL)
710      {
711         numTokens++;
712         if(numTokens >= 24)
713         {
714            validPath = 0;
715            break;
716         }
717      }
718      else
719      {
720         break;
721      }
722    }
723
724    if(validPath == 1)
725    {
726       snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
727       for(i=1; i<numTokens-1; i++)
728       {
729          // create folders
730          strncat(createPath, "/", DbPathMaxLen-1);
731          strncat(createPath, tokenArray[i], DbPathMaxLen-1);
732          mkdir(createPath, 0744);
733       }
734       // finally create the file
735       strncat(createPath, "/", DbPathMaxLen-1);
736       strncat(createPath, tokenArray[i], DbPathMaxLen-1);
737       rval = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
738       close(rval);
739    }
740    else
741    {
742       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFileAndPath ==> no valid path to create:"), DLT_STRING(path));
743    }
744
745    return rval;
746 }
747
748
749
750 int pclGetPosixPermission(PersistencePermission_e permission)
751 {
752    int posixPerm = 0;
753
754    switch( (int)permission)
755    {
756    case PersistencePermission_ReadWrite:
757       posixPerm = O_RDWR;
758       break;
759    case PersistencePermission_ReadOnly:
760       posixPerm = O_RDONLY;
761       break;
762    case PersistencePermission_WriteOnly:
763       posixPerm = O_WRONLY;
764       break;
765    default:
766       posixPerm = O_RDONLY;
767       break;
768    }
769
770    return posixPerm;
771 }
772
773
774