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 );
54 char* gpConfigFileMap = 0;
55 char* gpTokenArray[TOKENARRAYSIZE] = {0};
56 int gTokenCounter = 0;
57 unsigned int gConfigFileSize = 0;
61 static jsw_rbtree_t *gRb_tree_bl = NULL;
64 // local function prototypes
65 int need_backup_key(unsigned int key);
68 void fillFileBackupCharTokenArray()
72 char* tmpPointer = gpConfigFileMap;
74 // set the first pointer to the start of the file
75 gpTokenArray[blankCount] = tmpPointer;
78 while(i < gConfigFileSize)
80 if( ((unsigned int)*tmpPointer < 127)
81 && ((unsigned int)*tmpPointer >= 0))
83 if(1 != gCharLookup[(unsigned int)*tmpPointer])
87 // check if we are at the end of the token array
88 if(blankCount >= TOKENARRAYSIZE)
92 gpTokenArray[blankCount] = tmpPointer+1;
103 void createAndStoreFileNames()
107 const char* gFilePostFix = ".pers";
108 const char* gKeyPathFormat = "/%s/%s/%s/%s/%s%s";
112 gRb_tree_bl = jsw_rbnew(key_val_cmp, key_val_dup, key_val_rel);
114 if(gRb_tree_bl != NULL)
120 snprintf(path, 128, gKeyPathFormat, gpTokenArray[j+2], // storage type
121 gpTokenArray[j+3], // policy id
122 gpTokenArray[j+4], // profileID
123 gpTokenArray[j], // application id
124 gpTokenArray[j+1], // filename
125 gFilePostFix); // file postfix
127 // asign key and value to the rbtree item
128 item = malloc(sizeof(key_value_s));
131 item->key = pclCrc32(0, (unsigned char*)path, strlen(path));
132 // we don't need the path name here, we just need to know that this key is available in the tree
134 jsw_rbinsert(gRb_tree_bl, item);
138 if(gpTokenArray[j] == NULL)
148 int readBlacklistConfigFile(const char* filename)
159 memset(&buffer, 0, sizeof(buffer));
160 status = stat(filename, &buffer);
163 gConfigFileSize = buffer.st_size;
166 fd = open(filename, O_RDONLY);
169 DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file open"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
173 // check for empty file
174 if(gConfigFileSize == 0)
176 DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("configReader::readConfigFile ==> Error file size is 0:"), DLT_STRING(filename));
181 // map the config file into memory
182 gpConfigFileMap = (char*)mmap(0, gConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0);
184 if (gpConfigFileMap == MAP_FAILED)
188 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("configReader::readConfigFile ==> Error mapping the file:"), DLT_STRING(filename), DLT_STRING(strerror(errno)) );
193 // reset the token counter
196 fillFileBackupCharTokenArray();
198 // create filenames and store them in the tree
199 createAndStoreFileNames();
201 munmap(gpConfigFileMap, gConfigFileSize);
215 int need_backup_key(unsigned int key)
218 key_value_s* item = NULL;
219 key_value_s* foundItem = NULL;
221 item = malloc(sizeof(key_value_s));
222 if(item != NULL && gRb_tree_bl != NULL)
225 foundItem = (key_value_s*)jsw_rbfind(gRb_tree_bl, item);
226 if(foundItem != NULL)
238 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("need_backup_key ==> item or gRb_tree_bl is NULL"));
245 /// compare function for tree key_value_s item
246 int key_val_cmp(const void *p1, const void *p2 )
252 first = (key_value_s*)p1;
253 second = (key_value_s*)p2;
255 if(second->key == first->key)
259 else if(second->key < first->key)
271 /// duplicate function for key_value_s item
272 void* key_val_dup(void *p)
275 key_value_s* src = NULL;
276 key_value_s* dst = NULL;
278 src = (key_value_s*)p;
279 value_size = strlen(src->value)+1;
281 // allocate memory for node
282 dst = malloc(sizeof(key_value_s));
285 // duplicate hash key
289 dst->value = malloc(value_size);
290 if(dst->value != NULL)
291 strncpy(dst->value, src->value, value_size);
298 /// release function for key_value_s item
299 void key_val_rel(void *p )
301 key_value_s* rel = NULL;
302 rel = (key_value_s*)p;
304 if(rel->value != NULL)
312 int pclBackupDoFileCopy(int srcFd, int dstFd)
315 memset(&buf, 0, sizeof(buf));
318 return sendfile(dstFd, srcFd, 0, buf.st_size);
322 int pclCreateFile(const char* path)
324 const char* delimiters = "/\n"; // search for blank and end of line
325 char* tokenArray[24];
326 char thePath[DbPathMaxLen] = {0};
327 int numTokens = 0, i = 0, validPath = 1;
330 strncpy(thePath, path, DbPathMaxLen);
332 tokenArray[numTokens++] = strtok(thePath, delimiters);
333 while(tokenArray[numTokens-1] != NULL )
335 tokenArray[numTokens] = strtok(NULL, delimiters);
336 if(tokenArray[numTokens] != NULL)
353 char createPath[DbPathMaxLen] = {0};
354 snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] );
355 for(i=1; i<numTokens-1; i++)
358 strncat(createPath, "/", DbPathMaxLen-1);
359 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
360 mkdir(createPath, 0744);
362 // finally create the file
363 strncat(createPath, "/", DbPathMaxLen-1);
364 strncat(createPath, tokenArray[i], DbPathMaxLen-1);
366 handle = pfcOpenFile(createPath, CreateFile);
368 handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
373 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateFile ==> no valid path to create: "), DLT_STRING(path) );
380 int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags)
382 int handle = 0, readSize = 0;
383 int backupAvail = 0, csumAvail = 0;
384 int fdCsum = 0, fdBackup = 0;
386 char origCsumBuf[ChecksumBufSize] = {0};
387 char backCsumBuf[ChecksumBufSize] = {0};
388 char csumBuf[ChecksumBufSize] = {0};
390 // check if we have a backup and checksum file
391 backupAvail = access(backupPath, F_OK);
392 csumAvail = access(csumPath, F_OK);
394 // *************************************************
395 // there is a backup file and a checksum
396 // *************************************************
397 if( (backupAvail == 0) && (csumAvail == 0) )
399 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is a backup file AND a checksum"));
400 // calculate checksum form backup file
401 fdBackup = open(backupPath, O_RDONLY);
404 pclCalcCrc32Csum(fdBackup, backCsumBuf);
406 fdCsum = open(csumPath, O_RDONLY);
409 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
412 if(strcmp(csumBuf, backCsumBuf) == 0)
414 // checksum matches ==> replace with original file
415 handle = pclRecoverFromBackup(fdBackup, origPath);
419 // checksum does not match, check checksum with original file
420 handle = open(origPath, openFlags);
423 pclCalcCrc32Csum(handle, origCsumBuf);
424 if(strcmp(csumBuf, origCsumBuf) != 0)
427 handle = -1; // error: file corrupt
429 // else case: checksum matches ==> keep original file ==> nothing to do
435 handle = -1; // error: file corrupt
444 handle = -1; // error: file corrupt
453 // *************************************************
454 // there is ONLY a checksum file
455 // *************************************************
456 else if(csumAvail == 0)
458 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a checksum file"));
460 fdCsum = open(csumPath, O_RDONLY);
463 readSize = read(fdCsum, csumBuf, ChecksumBufSize);
466 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclVerifyConsistency => read checksum: invalid readSize"));
470 // calculate the checksum form the original file to see if it matches
471 handle = open(origPath, openFlags);
474 pclCalcCrc32Csum(handle, origCsumBuf);
476 if(strcmp(csumBuf, origCsumBuf) != 0)
479 handle = -1; // checksum does NOT match ==> error: file corrupt
481 // else case: checksum matches ==> keep original file ==> nothing to do
486 handle = -1; // error: file corrupt
492 handle = -1; // error: file corrupt
495 // *************************************************
496 // there is ONLY a backup file
497 // *************************************************
498 else if(backupAvail == 0)
500 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclVerifyConsistency => there is ONLY a backup file"));
502 // calculate checksum form backup file
503 fdBackup = open(backupPath, O_RDONLY);
506 pclCalcCrc32Csum(fdBackup, backCsumBuf);
509 // calculate the checksum form the original file to see if it matches
510 handle = open(origPath, openFlags);
513 pclCalcCrc32Csum(handle, origCsumBuf);
515 if(strcmp(backCsumBuf, origCsumBuf) != 0)
518 handle = -1; // checksum does NOT match ==> error: file corrupt
520 // else case: checksum matches ==> keep original file ==> nothing to do
526 handle = -1; // error: file corrupt
532 handle = -1; // error: file corrupt
535 // for else case: nothing to do
538 // if we are in an inconsistent state: delete file, backup and checksum
551 int pclRecoverFromBackup(int backupFd, const char* original)
555 handle = open(original, O_TRUNC | O_RDWR);
558 // copy data from one file to another
559 if(pclBackupDoFileCopy(backupFd, handle) == -1)
561 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclRecoverFromBackup => couldn't write whole buffer"));
570 int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf)
572 int dstFd = 0, csfd = 0;
575 if(access(dstPath, F_OK) != 0)
578 char pathToCreate[DbPathMaxLen] = {0};
579 strncpy(pathToCreate, dstPath, DbPathMaxLen);
581 handle = pclCreateFile(pathToCreate);
582 close(handle); // don't need the open file
585 // create checksum file and and write checksum
586 csfd = open(csumPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
589 int csumSize = strlen(csumBuf);
590 if(write(csfd, csumBuf, csumSize) != csumSize)
592 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to write checksum to file"));
598 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to create checksum file:"), DLT_STRING(strerror(errno)) );
601 // create backup file, user and group has read/write permission, others have read permission
602 dstFd = open(dstPath, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
606 // remember the current position
607 curPos = lseek(srcfd, 0, SEEK_CUR);
609 // copy data from one file to another
610 if((readSize = pclBackupDoFileCopy(srcfd, dstFd)) == -1)
612 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error copying file"));
615 if(close(dstFd) == -1)
617 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pcl_create_backup => error closing fd"));
620 // set back to the position
621 lseek(srcfd, curPos, SEEK_SET);
625 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclCreateBackup => failed to open backup file"),
626 DLT_STRING(dstPath), DLT_STRING(strerror(errno)));
634 int pclCalcCrc32Csum(int fd, char crc32sum[])
644 buf = malloc((unsigned int)statBuf.st_size);
649 // remember the current position
650 curPos = lseek(fd, 0, SEEK_CUR);
654 // set to beginning of the file
655 lseek(fd, 0, SEEK_SET);
658 while((rval = read(fd, buf, statBuf.st_size)) > 0)
660 unsigned int crc = 0;
661 crc = pclCrc32(crc, (unsigned char*)buf, statBuf.st_size);
662 snprintf(crc32sum, ChecksumBufSize-1, "%x", crc);
665 // set back to the position
666 lseek(fd, curPos, SEEK_SET);
680 int pclBackupNeeded(const char* path)
682 return need_backup_key(pclCrc32(0, (const unsigned char*)path, strlen(path)));
687 int pclGetPosixPermission(PersistencePermission_e permission)
691 switch( (int)permission)
693 case PersistencePermission_ReadWrite:
696 case PersistencePermission_ReadOnly:
697 posixPerm = O_RDONLY;
699 case PersistencePermission_WriteOnly:
700 posixPerm = O_WRONLY;
703 posixPerm = O_RDONLY;