1 /******************************************************************************
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 ******************************************************************************/
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
19 #include "persistence_client_library_backup_filelist.h"
20 #include "persistence_client_library_handle.h"
22 #include "../include_protected/crc32.h"
23 #include "../include_protected/persistence_client_library_data_organization.h"
34 #include <sys/sendfile.h>
37 /// structure definition for a key value item
38 typedef struct _key_value_s
45 void key_val_rel(void *p);
47 void* key_val_dup(void *p);
49 int key_val_cmp(const void *p1, const void *p2 );
53 /// the size of the token array
60 const char gCharLookup[] =
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 (~)
69 char* gpConfigFileMap = 0;
70 char* gpTokenArray[TOKENARRAYSIZE] = {0};
71 int gTokenCounter = 0;
72 unsigned int gConfigFileSize = 0;
76 static jsw_rbtree_t *gRb_tree_bl = NULL;
78 void fillCharTokenArray()
82 char* tmpPointer = gpConfigFileMap;
84 // set the first pointer to the start of the file
85 gpTokenArray[blankCount] = tmpPointer;
88 while(i < gConfigFileSize)
90 if( ((unsigned int)*tmpPointer < 127)
91 && ((unsigned int)*tmpPointer >= 0))
93 if(1 != gCharLookup[(unsigned int)*tmpPointer])
97 // check if we are at the end of the token array
98 if(blankCount >= TOKENARRAYSIZE)
102 gpTokenArray[blankCount] = tmpPointer+1;
113 void createAndStoreFileNames()
117 const char* gFilePostFix = ".pers";
118 const char* gKeyPathFormat = "/%s/%s/%s/%s/%s%s";
122 gRb_tree_bl = jsw_rbnew(key_val_cmp, key_val_dup, key_val_rel);
124 if(gRb_tree_bl != NULL)
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
137 // asign key and value to the rbtree item
138 item = malloc(sizeof(key_value_s));
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
144 jsw_rbinsert(gRb_tree_bl, item);
148 if(gpTokenArray[j] == NULL)
158 int readBlacklistConfigFile(const char* filename)
169 memset(&buffer, 0, sizeof(buffer));
170 status = stat(filename, &buffer);
173 gConfigFileSize = buffer.st_size;
176 fd = open(filename, O_RDONLY);
179 DLT_LOG(gDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file open"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
183 // check for empty file
184 if(gConfigFileSize == 0)
186 DLT_LOG(gDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file size is 0:"), DLT_STRING(filename));
191 // map the config file into memory
192 gpConfigFileMap = (char*)mmap(0, gConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0);
194 if (gpConfigFileMap == MAP_FAILED)
198 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("configReader::readConfigFile ==> Error mapping the file:"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
203 // reset the token counter
206 fillCharTokenArray();
208 // create filenames and store them in the tree
209 createAndStoreFileNames();
211 munmap(gpConfigFileMap, gConfigFileSize);
225 int need_backup_key(unsigned int key)
228 key_value_s* item = NULL;
229 key_value_s* foundItem = NULL;
231 item = malloc(sizeof(key_value_s));
232 if(item != NULL && gRb_tree_bl != NULL)
235 foundItem = (key_value_s*)jsw_rbfind(gRb_tree_bl, item);
236 if(foundItem != NULL)
248 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("need_backup_key ==> item or gRb_tree_bl is NULL"));
255 /// compare function for tree key_value_s item
256 int key_val_cmp(const void *p1, const void *p2 )
262 first = (key_value_s*)p1;
263 second = (key_value_s*)p2;
265 if(second->key == first->key)
269 else if(second->key < first->key)
281 /// duplicate function for key_value_s item
282 void* key_val_dup(void *p)
285 key_value_s* src = NULL;
286 key_value_s* dst = NULL;
288 src = (key_value_s*)p;
289 value_size = strlen(src->value)+1;
291 // allocate memory for node
292 dst = malloc(sizeof(key_value_s));
295 // duplicate hash key
299 dst->value = malloc(value_size);
300 if(dst->value != NULL)
301 strncpy(dst->value, src->value, value_size);
308 /// release function for key_value_s item
309 void key_val_rel(void *p )
311 key_value_s* rel = NULL;
312 rel = (key_value_s*)p;
314 if(rel->value != NULL)
322 int pclBackupDoFileCopy(int srcFd, int dstFd)
325 memset(&buf, 0, sizeof(buf));
328 return sendfile(dstFd, srcFd, 0, buf.st_size);
332 int pclCreateFile(const char* path)
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;
340 tokenArray[numTokens++] = strtok(thePath, delimiters);
341 while(tokenArray[numTokens-1] != NULL )
343 tokenArray[numTokens] = strtok(NULL, delimiters);
344 if(tokenArray[numTokens] != NULL)
361 char createPath[DbPathMaxLen] = {0};
362 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
363 for(i=1; i<numTokens-1; i++)
366 strncat(createPath, "/", DbPathMaxLen-1);
367 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
368 mkdir(createPath, 0744);
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);
376 if(handle < MaxPersHandle)
378 __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
383 handle = EPERS_MAXHANDLE;
389 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
396 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
398 int handle = 0, readSize = 0;
399 int backupAvail = 0, csumAvail = 0;
400 int fdCsum = 0, fdBackup = 0;
402 char origCsumBuf[ChecksumBufSize] = {0};
403 char backCsumBuf[ChecksumBufSize] = {0};
404 char csumBuf[ChecksumBufSize] = {0};
406 // check if we have a backup and checksum file
407 backupAvail = access(backupPath, F_OK);
408 csumAvail = access(csumPath, F_OK);
410 // *************************************************
411 // there is a backup file and a checksum
412 // *************************************************
413 if( (backupAvail == 0) && (csumAvail == 0) )
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);
420 pclCalcCrc32Csum(fdBackup, backCsumBuf);
422 fdCsum = open(csumPath, O_RDONLY);
425 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
428 if(strcmp(csumBuf, backCsumBuf) == 0)
430 // checksum matches ==> replace with original file
431 handle = pclRecoverFromBackup(fdBackup, origPath);
435 // checksum does not match, check checksum with original file
436 handle = open(origPath, openFlags);
439 pclCalcCrc32Csum(handle, origCsumBuf);
440 if(strcmp(csumBuf, origCsumBuf) != 0)
443 handle = -1; // error: file corrupt
445 // else case: checksum matches ==> keep original file ==> nothing to do
451 handle = -1; // error: file corrupt
460 handle = -1; // error: file corrupt
469 // *************************************************
470 // there is ONLY a checksum file
471 // *************************************************
472 else if(csumAvail == 0)
474 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
476 fdCsum = open(csumPath, O_RDONLY);
479 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
482 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
486 // calculate the checksum form the original file to see if it matches
487 handle = open(origPath, openFlags);
490 pclCalcCrc32Csum(handle, origCsumBuf);
492 if(strcmp(csumBuf, origCsumBuf) != 0)
495 handle = -1; // checksum does NOT match ==> error: file corrupt
497 // else case: checksum matches ==> keep original file ==> nothing to do
502 handle = -1; // error: file corrupt
508 handle = -1; // error: file corrupt
511 // *************************************************
512 // there is ONLY a backup file
513 // *************************************************
514 else if(backupAvail == 0)
516 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
518 // calculate checksum form backup file
519 fdBackup = open(backupPath, O_RDONLY);
522 pclCalcCrc32Csum(fdBackup, backCsumBuf);
525 // calculate the checksum form the original file to see if it matches
526 handle = open(origPath, openFlags);
529 pclCalcCrc32Csum(handle, origCsumBuf);
531 if(strcmp(backCsumBuf, origCsumBuf) != 0)
534 handle = -1; // checksum does NOT match ==> error: file corrupt
536 // else case: checksum matches ==> keep original file ==> nothing to do
542 handle = -1; // error: file corrupt
548 handle = -1; // error: file corrupt
551 // for else case: nothing to do
554 // if we are in an inconsistent state: delete file, backup and checksum
567 int pclRecoverFromBackup(int backupFd, const char* original)
571 handle = open(original, O_TRUNC | O_RDWR);
574 // copy data from one file to another
575 if((handle = pclBackupDoFileCopy(backupFd, handle)) == -1)
577 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
586 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
588 int dstFd = 0, csfd = 0;
591 if(access(dstPath, F_OK) != 0)
593 char pathToCreate[DbPathMaxLen] = {0};
594 strncpy(pathToCreate, dstPath, DbPathMaxLen);
595 pclCreateFileAndPath(pathToCreate);
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);
602 int csumSize = strlen(csumBuf);
603 if(write(csfd, csumBuf, csumSize) != csumSize)
605 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
611 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
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);
619 // remember the current position
620 curPos = lseek(srcfd, 0, SEEK_CUR);
622 // copy data from one file to another
623 if((readSize = pclBackupDoFileCopy(srcfd, dstFd)) == -1)
625 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
628 if(close(dstFd) == -1)
630 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
633 // set back to the position
634 lseek(srcfd, curPos, SEEK_SET);
638 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
639 DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
647 int pclCalcCrc32Csum(int fd, char crc32sum[])
657 buf = malloc((unsigned int)statBuf.st_size);
662 // remember the current position
663 curPos = lseek(fd, 0, SEEK_CUR);
667 // set to beginning of the file
668 lseek(fd, 0, SEEK_SET);
671 while((rval = read(fd, buf, statBuf.st_size)) > 0)
673 unsigned int crc = 0;
674 crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
675 snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
678 // set back to the position
679 lseek(fd, curPos, SEEK_SET);
689 int pclBackupNeeded(const char* path)
691 return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
696 int pclCreateFileAndPath(const char* path)
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;
705 tokenArray[numTokens++] = strtok(thePath, delimiters);
706 while(tokenArray[numTokens-1] != NULL )
708 tokenArray[numTokens] = strtok(NULL, delimiters);
709 if(tokenArray[numTokens] != NULL)
726 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
727 for(i=1; i<numTokens-1; i++)
730 strncat(createPath, "/", DbPathMaxLen-1);
731 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
732 mkdir(createPath, 0744);
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);
742 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFileAndPath ==> no valid path to create:"), DLT_STRING(path));
750 int pclGetPosixPermission(PersistencePermission_e permission)
754 switch( (int)permission)
756 case PersistencePermission_ReadWrite:
759 case PersistencePermission_ReadOnly:
760 posixPerm = O_RDONLY;
762 case PersistencePermission_WriteOnly:
763 posixPerm = O_WRONLY;
766 posixPerm = O_RDONLY;