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[DbPathMaxLen] = {0};
337 int numTokens = 0, i = 0, validPath = 1;
340 strncpy(thePath, path, DbPathMaxLen);
342 tokenArray[numTokens++] = strtok(thePath, delimiters);
343 while(tokenArray[numTokens-1] != NULL )
345 tokenArray[numTokens] = strtok(NULL, delimiters);
346 if(tokenArray[numTokens] != NULL)
363 char createPath[DbPathMaxLen] = {0};
364 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
365 for(i=1; i<numTokens-1; i++)
368 strncat(createPath, "/", DbPathMaxLen-1);
369 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
370 mkdir(createPath, 0744);
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);
379 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
386 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
388 int handle = 0, readSize = 0;
389 int backupAvail = 0, csumAvail = 0;
390 int fdCsum = 0, fdBackup = 0;
392 char origCsumBuf[ChecksumBufSize] = {0};
393 char backCsumBuf[ChecksumBufSize] = {0};
394 char csumBuf[ChecksumBufSize] = {0};
396 // check if we have a backup and checksum file
397 backupAvail = access(backupPath, F_OK);
398 csumAvail = access(csumPath, F_OK);
400 // *************************************************
401 // there is a backup file and a checksum
402 // *************************************************
403 if( (backupAvail == 0) && (csumAvail == 0) )
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);
410 pclCalcCrc32Csum(fdBackup, backCsumBuf);
412 fdCsum = open(csumPath, O_RDONLY);
415 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
418 if(strcmp(csumBuf, backCsumBuf) == 0)
420 // checksum matches ==> replace with original file
421 handle = pclRecoverFromBackup(fdBackup, origPath);
425 // checksum does not match, check checksum with original file
426 handle = open(origPath, openFlags);
429 pclCalcCrc32Csum(handle, origCsumBuf);
430 if(strcmp(csumBuf, origCsumBuf) != 0)
433 handle = -1; // error: file corrupt
435 // else case: checksum matches ==> keep original file ==> nothing to do
441 handle = -1; // error: file corrupt
450 handle = -1; // error: file corrupt
459 // *************************************************
460 // there is ONLY a checksum file
461 // *************************************************
462 else if(csumAvail == 0)
464 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
466 fdCsum = open(csumPath, O_RDONLY);
469 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
472 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
476 // calculate the checksum form the original file to see if it matches
477 handle = open(origPath, openFlags);
480 pclCalcCrc32Csum(handle, origCsumBuf);
482 if(strcmp(csumBuf, origCsumBuf) != 0)
485 handle = -1; // checksum does NOT match ==> error: file corrupt
487 // else case: checksum matches ==> keep original file ==> nothing to do
492 handle = -1; // error: file corrupt
498 handle = -1; // error: file corrupt
501 // *************************************************
502 // there is ONLY a backup file
503 // *************************************************
504 else if(backupAvail == 0)
506 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
508 // calculate checksum form backup file
509 fdBackup = open(backupPath, O_RDONLY);
512 pclCalcCrc32Csum(fdBackup, backCsumBuf);
515 // calculate the checksum form the original file to see if it matches
516 handle = open(origPath, openFlags);
519 pclCalcCrc32Csum(handle, origCsumBuf);
521 if(strcmp(backCsumBuf, origCsumBuf) != 0)
524 handle = -1; // checksum does NOT match ==> error: file corrupt
526 // else case: checksum matches ==> keep original file ==> nothing to do
532 handle = -1; // error: file corrupt
538 handle = -1; // error: file corrupt
541 // for else case: nothing to do
544 // if we are in an inconsistent state: delete file, backup and checksum
557 int pclRecoverFromBackup(int backupFd, const char* original)
561 handle = open(original, O_TRUNC | O_RDWR);
564 // copy data from one file to another
565 if((handle = pclBackupDoFileCopy(backupFd, handle)) == -1)
567 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
576 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
578 int dstFd = 0, csfd = 0;
581 if(access(dstPath, F_OK) != 0)
584 char pathToCreate[DbPathMaxLen] = {0};
585 strncpy(pathToCreate, dstPath, DbPathMaxLen);
587 handle = pclCreateFile(pathToCreate);
588 close(handle); // don't need the open file
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);
595 int csumSize = strlen(csumBuf);
596 if(write(csfd, csumBuf, csumSize) != csumSize)
598 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
604 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
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);
612 // remember the current position
613 curPos = lseek(srcfd, 0, SEEK_CUR);
615 // copy data from one file to another
616 if((readSize = pclBackupDoFileCopy(srcfd, dstFd)) == -1)
618 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
621 if(close(dstFd) == -1)
623 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
626 // set back to the position
627 lseek(srcfd, curPos, SEEK_SET);
631 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
632 DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
640 int pclCalcCrc32Csum(int fd, char crc32sum[])
650 buf = malloc((unsigned int)statBuf.st_size);
655 // remember the current position
656 curPos = lseek(fd, 0, SEEK_CUR);
660 // set to beginning of the file
661 lseek(fd, 0, SEEK_SET);
664 while((rval = read(fd, buf, statBuf.st_size)) > 0)
666 unsigned int crc = 0;
667 crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
668 snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
671 // set back to the position
672 lseek(fd, curPos, SEEK_SET);
682 int pclBackupNeeded(const char* path)
684 return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
689 int pclGetPosixPermission(PersistencePermission_e permission)
693 switch( (int)permission)
695 case PersistencePermission_ReadWrite:
698 case PersistencePermission_ReadOnly:
699 posixPerm = O_RDONLY;
701 case PersistencePermission_WriteOnly:
702 posixPerm = O_WRONLY;
705 posixPerm = O_RDONLY;