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"
24 #include "persistence_client_library_data_organization.h"
28 #include <persistence_file_cache.h>
36 #include <sys/sendfile.h>
39 /// structure definition for a key value item
40 typedef struct _key_value_s
47 void key_val_rel(void *p);
49 void* key_val_dup(void *p);
51 int key_val_cmp(const void *p1, const void *p2 );
55 /// the size of the token array
62 const char gCharLookup[] =
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 (~)
71 char* gpConfigFileMap = 0;
72 char* gpTokenArray[TOKENARRAYSIZE] = {0};
73 int gTokenCounter = 0;
74 unsigned int gConfigFileSize = 0;
78 static jsw_rbtree_t *gRb_tree_bl = NULL;
81 // local function prototypes
82 int need_backup_key(unsigned int key);
85 void fillCharTokenArray()
89 char* tmpPointer = gpConfigFileMap;
91 // set the first pointer to the start of the file
92 gpTokenArray[blankCount] = tmpPointer;
95 while(i < gConfigFileSize)
97 if( ((unsigned int)*tmpPointer < 127)
98 && ((unsigned int)*tmpPointer >= 0))
100 if(1 != gCharLookup[(unsigned int)*tmpPointer])
104 // check if we are at the end of the token array
105 if(blankCount >= TOKENARRAYSIZE)
109 gpTokenArray[blankCount] = tmpPointer+1;
120 void createAndStoreFileNames()
124 const char* gFilePostFix = ".pers";
125 const char* gKeyPathFormat = "/%s/%s/%s/%s/%s%s";
129 gRb_tree_bl = jsw_rbnew(key_val_cmp, key_val_dup, key_val_rel);
131 if(gRb_tree_bl != NULL)
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
144 // asign key and value to the rbtree item
145 item = malloc(sizeof(key_value_s));
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
151 jsw_rbinsert(gRb_tree_bl, item);
155 if(gpTokenArray[j] == NULL)
165 int readBlacklistConfigFile(const char* filename)
176 memset(&buffer, 0, sizeof(buffer));
177 status = stat(filename, &buffer);
180 gConfigFileSize = buffer.st_size;
183 fd = open(filename, O_RDONLY);
186 DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file open"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
190 // check for empty file
191 if(gConfigFileSize == 0)
193 DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file size is 0:"), DLT_STRING(filename));
198 // map the config file into memory
199 gpConfigFileMap = (char*)mmap(0, gConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0);
201 if (gpConfigFileMap == MAP_FAILED)
205 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("configReader::readConfigFile ==> Error mapping the file:"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
210 // reset the token counter
213 fillCharTokenArray();
215 // create filenames and store them in the tree
216 createAndStoreFileNames();
218 munmap(gpConfigFileMap, gConfigFileSize);
232 int need_backup_key(unsigned int key)
235 key_value_s* item = NULL;
236 key_value_s* foundItem = NULL;
238 item = malloc(sizeof(key_value_s));
239 if(item != NULL && gRb_tree_bl != NULL)
242 foundItem = (key_value_s*)jsw_rbfind(gRb_tree_bl, item);
243 if(foundItem != NULL)
255 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("need_backup_key ==> item or gRb_tree_bl is NULL"));
262 /// compare function for tree key_value_s item
263 int key_val_cmp(const void *p1, const void *p2 )
269 first = (key_value_s*)p1;
270 second = (key_value_s*)p2;
272 if(second->key == first->key)
276 else if(second->key < first->key)
288 /// duplicate function for key_value_s item
289 void* key_val_dup(void *p)
292 key_value_s* src = NULL;
293 key_value_s* dst = NULL;
295 src = (key_value_s*)p;
296 value_size = strlen(src->value)+1;
298 // allocate memory for node
299 dst = malloc(sizeof(key_value_s));
302 // duplicate hash key
306 dst->value = malloc(value_size);
307 if(dst->value != NULL)
308 strncpy(dst->value, src->value, value_size);
315 /// release function for key_value_s item
316 void key_val_rel(void *p )
318 key_value_s* rel = NULL;
319 rel = (key_value_s*)p;
321 if(rel->value != NULL)
329 int pclBackupDoFileCopy(int srcFd, int dstFd)
332 memset(&buf, 0, sizeof(buf));
335 return sendfile(dstFd, srcFd, 0, buf.st_size);
339 int pclCreateFile(const char* path)
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;
347 strncpy(thePath, path, DbPathMaxLen);
349 tokenArray[numTokens++] = strtok(thePath, delimiters);
350 while(tokenArray[numTokens-1] != NULL )
352 tokenArray[numTokens] = strtok(NULL, delimiters);
353 if(tokenArray[numTokens] != NULL)
370 char createPath[DbPathMaxLen] = {0};
371 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
372 for(i=1; i<numTokens-1; i++)
375 strncat(createPath, "/", DbPathMaxLen-1);
376 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
377 mkdir(createPath, 0744);
379 // finally create the file
380 strncat(createPath, "/", DbPathMaxLen-1);
381 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
383 handle = pfcOpenFile(createPath, CreateFile);
385 handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
390 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
397 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
399 int handle = 0, readSize = 0;
400 int backupAvail = 0, csumAvail = 0;
401 int fdCsum = 0, fdBackup = 0;
403 char origCsumBuf[ChecksumBufSize] = {0};
404 char backCsumBuf[ChecksumBufSize] = {0};
405 char csumBuf[ChecksumBufSize] = {0};
407 // check if we have a backup and checksum file
408 backupAvail = access(backupPath, F_OK);
409 csumAvail = access(csumPath, F_OK);
411 // *************************************************
412 // there is a backup file and a checksum
413 // *************************************************
414 if( (backupAvail == 0) && (csumAvail == 0) )
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);
421 pclCalcCrc32Csum(fdBackup, backCsumBuf);
423 fdCsum = open(csumPath, O_RDONLY);
426 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
429 if(strcmp(csumBuf, backCsumBuf) == 0)
431 // checksum matches ==> replace with original file
432 handle = pclRecoverFromBackup(fdBackup, origPath);
436 // checksum does not match, check checksum with original file
437 handle = open(origPath, openFlags);
440 pclCalcCrc32Csum(handle, origCsumBuf);
441 if(strcmp(csumBuf, origCsumBuf) != 0)
444 handle = -1; // error: file corrupt
446 // else case: checksum matches ==> keep original file ==> nothing to do
452 handle = -1; // error: file corrupt
461 handle = -1; // error: file corrupt
470 // *************************************************
471 // there is ONLY a checksum file
472 // *************************************************
473 else if(csumAvail == 0)
475 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
477 fdCsum = open(csumPath, O_RDONLY);
480 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
483 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
487 // calculate the checksum form the original file to see if it matches
488 handle = open(origPath, openFlags);
491 pclCalcCrc32Csum(handle, origCsumBuf);
493 if(strcmp(csumBuf, origCsumBuf) != 0)
496 handle = -1; // checksum does NOT match ==> error: file corrupt
498 // else case: checksum matches ==> keep original file ==> nothing to do
503 handle = -1; // error: file corrupt
509 handle = -1; // error: file corrupt
512 // *************************************************
513 // there is ONLY a backup file
514 // *************************************************
515 else if(backupAvail == 0)
517 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
519 // calculate checksum form backup file
520 fdBackup = open(backupPath, O_RDONLY);
523 pclCalcCrc32Csum(fdBackup, backCsumBuf);
526 // calculate the checksum form the original file to see if it matches
527 handle = open(origPath, openFlags);
530 pclCalcCrc32Csum(handle, origCsumBuf);
532 if(strcmp(backCsumBuf, origCsumBuf) != 0)
535 handle = -1; // checksum does NOT match ==> error: file corrupt
537 // else case: checksum matches ==> keep original file ==> nothing to do
543 handle = -1; // error: file corrupt
549 handle = -1; // error: file corrupt
552 // for else case: nothing to do
555 // if we are in an inconsistent state: delete file, backup and checksum
568 int pclRecoverFromBackup(int backupFd, const char* original)
572 handle = open(original, O_TRUNC | O_RDWR);
575 // copy data from one file to another
576 if(pclBackupDoFileCopy(backupFd, handle) == -1)
578 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
587 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
589 int dstFd = 0, csfd = 0;
592 if(access(dstPath, F_OK) != 0)
595 char pathToCreate[DbPathMaxLen] = {0};
596 strncpy(pathToCreate, dstPath, DbPathMaxLen);
598 handle = pclCreateFile(pathToCreate);
599 close(handle); // don't need the open file
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);
606 int csumSize = strlen(csumBuf);
607 if(write(csfd, csumBuf, csumSize) != csumSize)
609 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
615 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
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);
623 // remember the current position
624 curPos = lseek(srcfd, 0, SEEK_CUR);
626 // copy data from one file to another
627 if((readSize = pclBackupDoFileCopy(srcfd, dstFd)) == -1)
629 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
632 if(close(dstFd) == -1)
634 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
637 // set back to the position
638 lseek(srcfd, curPos, SEEK_SET);
642 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
643 DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
651 int pclCalcCrc32Csum(int fd, char crc32sum[])
661 buf = malloc((unsigned int)statBuf.st_size);
666 // remember the current position
667 curPos = lseek(fd, 0, SEEK_CUR);
671 // set to beginning of the file
672 lseek(fd, 0, SEEK_SET);
675 while((rval = read(fd, buf, statBuf.st_size)) > 0)
677 unsigned int crc = 0;
678 crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
679 snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
682 // set back to the position
683 lseek(fd, curPos, SEEK_SET);
697 int pclBackupNeeded(const char* path)
699 return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
704 int pclGetPosixPermission(PersistencePermission_e permission)
708 switch( (int)permission)
710 case PersistencePermission_ReadWrite:
713 case PersistencePermission_ReadOnly:
714 posixPerm = O_RDONLY;
716 case PersistencePermission_WriteOnly:
717 posixPerm = O_WRONLY;
720 posixPerm = O_RDONLY;