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"
36 /// structure definition for a key value item
37 typedef struct _key_value_s
44 void key_val_rel(void *p);
46 void* key_val_dup(void *p);
48 int key_val_cmp(const void *p1, const void *p2 );
52 /// the size of the token array
59 const char gCharLookup[] =
61 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)
62 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 (?)
63 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 (_)
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 // from 060 (') to 0x7E (~)
68 char* gpConfigFileMap = 0;
69 char* gpTokenArray[TOKENARRAYSIZE] = {0};
70 int gTokenCounter = 0;
71 unsigned int gConfigFileSize = 0;
75 static jsw_rbtree_t *gRb_tree_bl = NULL;
77 void fillCharTokenArray()
81 char* tmpPointer = gpConfigFileMap;
83 // set the first pointer to the start of the file
84 gpTokenArray[blankCount] = tmpPointer;
87 while(i < gConfigFileSize)
89 if( ((unsigned int)*tmpPointer < 127)
90 && ((unsigned int)*tmpPointer >= 0))
92 if(1 != gCharLookup[(unsigned int)*tmpPointer])
96 // check if we are at the end of the token array
97 if(blankCount >= TOKENARRAYSIZE)
101 gpTokenArray[blankCount] = tmpPointer+1;
112 void createAndStoreFileNames()
116 const char* gFilePostFix = ".pers";
117 const char* gKeyPathFormat = "/%s/%s/%s/%s/%s%s";
121 gRb_tree_bl = jsw_rbnew(key_val_cmp, key_val_dup, key_val_rel);
123 if(gRb_tree_bl != NULL)
129 snprintf(path, 128, gKeyPathFormat, gpTokenArray[j+2], // storage type
130 gpTokenArray[j+3], // policy id
131 gpTokenArray[j+4], // profileID
132 gpTokenArray[j], // application id
133 gpTokenArray[j+1], // filename
134 gFilePostFix); // file postfix
136 // asign key and value to the rbtree item
137 item = malloc(sizeof(key_value_s));
140 item->key = pclCrc32(0, (unsigned char*)path, strlen(path));
141 // we don't need the path name here, we just need to know that this key is available in the tree
143 jsw_rbinsert(gRb_tree_bl, item);
147 if(gpTokenArray[j] == NULL)
157 int readBlacklistConfigFile(const char* filename)
168 memset(&buffer, 0, sizeof(buffer));
169 status = stat(filename, &buffer);
172 gConfigFileSize = buffer.st_size;
175 fd = open(filename, O_RDONLY);
178 DLT_LOG(gDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file open"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
182 // check for empty file
183 if(gConfigFileSize == 0)
185 DLT_LOG(gDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file size is 0:"), DLT_STRING(filename));
190 // map the config file into memory
191 gpConfigFileMap = (char*)mmap(0, gConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0);
193 if (gpConfigFileMap == MAP_FAILED)
197 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("configReader::readConfigFile ==> Error mapping the file:"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
202 // reset the token counter
205 fillCharTokenArray();
207 // create filenames and store them in the tree
208 createAndStoreFileNames();
210 munmap(gpConfigFileMap, gConfigFileSize);
224 int need_backup_key(unsigned int key)
227 key_value_s* item = NULL;
228 key_value_s* foundItem = NULL;
230 item = malloc(sizeof(key_value_s));
231 if(item != NULL && gRb_tree_bl != NULL)
234 foundItem = (key_value_s*)jsw_rbfind(gRb_tree_bl, item);
235 if(foundItem != NULL)
247 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("need_backup_key ==> item or gRb_tree_bl is NULL"));
254 /// compare function for tree key_value_s item
255 int key_val_cmp(const void *p1, const void *p2 )
261 first = (key_value_s*)p1;
262 second = (key_value_s*)p2;
264 if(second->key == first->key)
268 else if(second->key < first->key)
280 /// duplicate function for key_value_s item
281 void* key_val_dup(void *p)
284 key_value_s* src = NULL;
285 key_value_s* dst = NULL;
287 src = (key_value_s*)p;
288 value_size = strlen(src->value)+1;
290 // allocate memory for node
291 dst = malloc(sizeof(key_value_s));
294 // duplicate hash key
298 dst->value = malloc(value_size);
299 if(dst->value != NULL)
300 strncpy(dst->value, src->value, value_size);
307 /// release function for key_value_s item
308 void key_val_rel(void *p )
310 key_value_s* rel = NULL;
311 rel = (key_value_s*)p;
313 if(rel->value != NULL)
321 int pclCreateFile(const char* path)
323 const char* delimiters = "/\n"; // search for blank and end of line
324 char* tokenArray[24];
325 char* thePath = (char*)path;
326 int numTokens = 0, i = 0, validPath = 1;
329 tokenArray[numTokens++] = strtok(thePath, delimiters);
330 while(tokenArray[numTokens-1] != NULL )
332 tokenArray[numTokens] = strtok(NULL, delimiters);
333 if(tokenArray[numTokens] != NULL)
350 char createPath[DbPathMaxLen] = {0};
351 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
352 for(i=1; i<numTokens-1; i++)
355 strncat(createPath, "/", DbPathMaxLen-1);
356 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
357 mkdir(createPath, 0744);
359 // finally create the file
360 strncat(createPath, "/", DbPathMaxLen-1);
361 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
362 handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
365 if(handle < MaxPersHandle)
367 __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
372 handle = EPERS_MAXHANDLE;
378 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
385 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
387 int handle = 0, readSize = 0;
388 int backupAvail = 0, csumAvail = 0;
389 int fdCsum = 0, fdBackup = 0;
391 char origCsumBuf[ChecksumBufSize] = {0};
392 char backCsumBuf[ChecksumBufSize] = {0};
393 char csumBuf[ChecksumBufSize] = {0};
395 // check if we have a backup and checksum file
396 backupAvail = access(backupPath, F_OK);
397 csumAvail = access(csumPath, F_OK);
399 // *************************************************
400 // there is a backup file and a checksum
401 // *************************************************
402 if( (backupAvail == 0) && (csumAvail == 0) )
404 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is a backup file AND a checksum"));
405 // calculate checksum form backup file
406 fdBackup = open(backupPath, O_RDONLY);
409 pclCalcCrc32Csum(fdBackup, backCsumBuf);
411 fdCsum = open(csumPath, O_RDONLY);
414 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
417 if(strcmp(csumBuf, backCsumBuf) == 0)
419 // checksum matches ==> replace with original file
420 handle = pclRecoverFromBackup(fdBackup, origPath);
424 // checksum does not match, check checksum with original file
425 handle = open(origPath, openFlags);
428 pclCalcCrc32Csum(handle, origCsumBuf);
429 if(strcmp(csumBuf, origCsumBuf) != 0)
432 handle = -1; // error: file corrupt
434 // else case: checksum matches ==> keep original file ==> nothing to do
440 handle = -1; // error: file corrupt
449 handle = -1; // error: file corrupt
458 // *************************************************
459 // there is ONLY a checksum file
460 // *************************************************
461 else if(csumAvail == 0)
463 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
465 fdCsum = open(csumPath, O_RDONLY);
468 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
471 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
475 // calculate the checksum form the original file to see if it matches
476 handle = open(origPath, openFlags);
479 pclCalcCrc32Csum(handle, origCsumBuf);
481 if(strcmp(csumBuf, origCsumBuf) != 0)
484 handle = -1; // checksum does NOT match ==> error: file corrupt
486 // else case: checksum matches ==> keep original file ==> nothing to do
491 handle = -1; // error: file corrupt
497 handle = -1; // error: file corrupt
500 // *************************************************
501 // there is ONLY a backup file
502 // *************************************************
503 else if(backupAvail == 0)
505 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
507 // calculate checksum form backup file
508 fdBackup = open(backupPath, O_RDONLY);
511 pclCalcCrc32Csum(fdBackup, backCsumBuf);
514 // calculate the checksum form the original file to see if it matches
515 handle = open(origPath, openFlags);
518 pclCalcCrc32Csum(handle, origCsumBuf);
520 if(strcmp(backCsumBuf, origCsumBuf) != 0)
523 handle = -1; // checksum does NOT match ==> error: file corrupt
525 // else case: checksum matches ==> keep original file ==> nothing to do
531 handle = -1; // error: file corrupt
537 handle = -1; // error: file corrupt
540 // for else case: nothing to do
543 // if we are in an inconsistent state: delete file, backup and checksum
556 int pclRecoverFromBackup(int backupFd, const char* original)
560 char buffer[RDRWBufferSize];
562 handle = open(original, O_TRUNC | O_RDWR);
565 // copy data from one file to another
566 while((readSize = read(backupFd, buffer, RDRWBufferSize)) > 0)
568 if(write(handle, buffer, readSize) != readSize)
570 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
582 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
584 int dstFd = 0, csfd = 0;
586 char buffer[RDRWBufferSize];
588 if(access(dstPath, F_OK) != 0)
590 char pathToCreate[DbPathMaxLen] = {0};
591 strncpy(pathToCreate, dstPath, DbPathMaxLen);
592 pclCreateFileAndPath(pathToCreate);
595 // create checksum file and and write checksum
596 csfd = open(csumPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
599 int csumSize = strlen(csumBuf);
600 if(write(csfd, csumBuf, csumSize) != csumSize)
602 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
608 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
611 // create backup file, user and group has read/write permission, others have read permission
612 dstFd = open(dstPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
616 // remember the current position
617 curPos = lseek(srcfd, 0, SEEK_CUR);
619 // copy data from one file to another
620 while((readSize = read(srcfd, buffer, RDRWBufferSize)) > 0)
622 if(write(dstFd, buffer, readSize) != readSize)
624 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => couldn't write whole buffer"));
630 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
632 if((readSize = close(dstFd)) == -1)
633 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
635 // set back to the position
636 lseek(srcfd, curPos, SEEK_SET);
640 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
641 DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
649 int pclCalcCrc32Csum(int fd, char crc32sum[])
659 buf = malloc((unsigned int)statBuf.st_size);
664 // remember the current position
665 curPos = lseek(fd, 0, SEEK_CUR);
669 // set to beginning of the file
670 lseek(fd, 0, SEEK_SET);
673 while((rval = read(fd, buf, statBuf.st_size)) > 0)
675 unsigned int crc = 0;
676 crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
677 snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
680 // set back to the position
681 lseek(fd, curPos, SEEK_SET);
691 int pclBackupNeeded(const char* path)
693 return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
698 int pclCreateFileAndPath(const char* path)
700 const char* delimiters = "/\n"; // search for blank and end of line
701 char* tokenArray[24];
702 char* thePath = (char*)path;
703 char createPath[DbPathMaxLen] = {0};
704 int numTokens = 0, i = 0, validPath = 1;
707 tokenArray[numTokens++] = strtok(thePath, delimiters);
708 while(tokenArray[numTokens-1] != NULL )
710 tokenArray[numTokens] = strtok(NULL, delimiters);
711 if(tokenArray[numTokens] != NULL)
728 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
729 for(i=1; i<numTokens-1; i++)
732 strncat(createPath, "/", DbPathMaxLen-1);
733 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
734 mkdir(createPath, 0744);
736 // finally create the file
737 strncat(createPath, "/", DbPathMaxLen-1);
738 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
739 rval = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
744 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFileAndPath ==> no valid path to create:"), DLT_STRING(path));
752 int pclGetPosixPermission(PersistencePermission_e permission)
756 switch( (int)permission)
758 case PersistencePermission_ReadWrite:
761 case PersistencePermission_ReadOnly:
762 posixPerm = O_RDONLY;
764 case PersistencePermission_WriteOnly:
765 posixPerm = O_WRONLY;
768 posixPerm = O_RDONLY;