diff options
author | Ingo Huerner <ingo.huerner@xse.de> | 2013-04-18 11:48:29 +0200 |
---|---|---|
committer | Ingo Huerner <ingo.huerner@xse.de> | 2013-04-18 11:48:29 +0200 |
commit | 20075d4a4ab86720f0c11dca55726847db61898f (patch) | |
tree | c68fbf9c96de5259193cd86e672908100751804b | |
parent | 515004b1f75c8e2be7101732110c5b50ce9920f6 (diff) | |
download | persistence-client-library-20075d4a4ab86720f0c11dca55726847db61898f.tar.gz |
Added reason to notification messages; started with backup file list implementation
-rw-r--r-- | include/persistence_client_library_error_def.h | 4 | ||||
-rw-r--r-- | include/persistence_client_library_key.h | 28 | ||||
-rw-r--r-- | include_protected/persistence_client_library_data_organization.h | 31 | ||||
-rw-r--r-- | include_protected/persistence_client_library_db_access.h | 13 | ||||
-rw-r--r-- | include_protected/persistence_client_library_rc_table.h | 2 | ||||
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/persistence_client_library.c | 39 | ||||
-rw-r--r-- | src/persistence_client_library_backup_filelist.c | 312 | ||||
-rw-r--r-- | src/persistence_client_library_backup_filelist.h | 38 | ||||
-rw-r--r-- | src/persistence_client_library_data_organization.c | 15 | ||||
-rw-r--r-- | src/persistence_client_library_db_access.c | 188 | ||||
-rw-r--r-- | src/persistence_client_library_dbus_service.c | 26 | ||||
-rw-r--r-- | src/persistence_client_library_file.c | 258 | ||||
-rw-r--r-- | src/persistence_client_library_key.c | 13 | ||||
-rw-r--r-- | src/persistence_client_library_prct_access.c | 6 | ||||
-rw-r--r-- | src/rbtree.c | 635 | ||||
-rw-r--r-- | src/rbtree.h | 99 | ||||
-rw-r--r-- | test/persistence_client_library_dbus_test.c | 7 |
18 files changed, 1504 insertions, 217 deletions
diff --git a/include/persistence_client_library_error_def.h b/include/persistence_client_library_error_def.h index 3cb5616..458af90 100644 --- a/include/persistence_client_library_error_def.h +++ b/include/persistence_client_library_error_def.h @@ -83,6 +83,10 @@ extern "C" { #define EPERS_DB_KEY_SIZE (-28) /// db value size is to long #define EPERS_DB_VALUE_SIZE (-29) +/// resource is not a key +#define EPERS_RES_NO_KEY (-30) +/// chnage notification signal could ne be sent +#define EPERS_NOTIFY_SIG (-30) /** diff --git a/include/persistence_client_library_key.h b/include/persistence_client_library_key.h index 56c5c3c..0afd071 100644 --- a/include/persistence_client_library_key.h +++ b/include/persistence_client_library_key.h @@ -32,7 +32,7 @@ extern "C" { #endif -#define PERSIST_KEYVALUEAPI_INTERFACE_VERSION (0x04000000U) +#define PERSIST_KEYVALUEAPI_INTERFACE_VERSION (0x04100000U) /** * status returned in notification structure @@ -53,16 +53,31 @@ typedef enum _pclNotifyStatus_e */ typedef struct _pclNotification_s { - pclNotifyStatus_e pclKeyNotify_Status; - unsigned int ldbid; - const char * resource_id; - unsigned int user_no; - unsigned int seat_no; + pclNotifyStatus_e pclKeyNotify_Status; /// notification status + unsigned int ldbid; /// logical db id + const char * resource_id; /// resource id + unsigned int user_no; /// user id + unsigned int seat_no; /// seat id } pclNotification_s; +enum pclShutdownTypeNotification +{ + NSM_SHUTDOWN_TYPE_FAST = 2, /// Client registered for fast lifecycle shutdown + NSM_SHUTDOWN_TYPE_NORMAL = 1 /// Client registered for normal lifecycle shutdown +}; + + +/// defiinition of the change callback typedef int(* pclChangeNotifyCallback_t)(pclNotification_s * notifyStruct); +/// library constructor +void pclLibraryConstructor(void) __attribute__((constructor)); + +/// library deconstructor +void pclLibraryDestructor(void) __attribute__((destructor)); + + /** * @brief delete persistent data * @@ -195,6 +210,7 @@ int pclKeyReadData(unsigned int ldbid, const char* resource_id, unsigned int use * @param callback notification callback * * @return positive value: registration OK; On error a negative value will be returned with th follwoing error codes: + * EPERS_RES_NO_KEY EPERS_NOKEYDATA EPERS_NOPRCTABLE */ int pclKeyRegisterNotifyOnChange(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no, pclChangeNotifyCallback_t callback); diff --git a/include_protected/persistence_client_library_data_organization.h b/include_protected/persistence_client_library_data_organization.h index f6fd120..c3e305a 100644 --- a/include_protected/persistence_client_library_data_organization.h +++ b/include_protected/persistence_client_library_data_organization.h @@ -24,7 +24,7 @@ extern "C" { #endif -#define PERSIST_CLIENT_LIBRARY_DATA_ORGANIZATION_INTERFACE_VERSION (0x01100000U) +#define PERSIST_CLIENT_LIBRARY_DATA_ORGANIZATION_INTERFACE_VERSION (0x01020000U) #include "../include/persistence_client_library_error_def.h" #include "../include/persistence_client_library_key.h" @@ -48,12 +48,17 @@ enum _PersistenceConstantDef NsmErrorStatus_OK = 1, NsmErrorStatus_Fail = -1, - ChecksumBufSize = 64, + ChecksumBufSize = 64, /// max checksum size + + DbusSubMatchSize = 12, /// max character sub match size + DbusMatchRuleSize = 300, /// max character size of the dbus match rule size PrctKeySize = 64, /// persistence resource config table max key size PrctValueSize = 256, /// persistence resource config table max value size PrctDbTableSize = 1024, /// number of persistence resource config tables to store + RDRWBufferSize = 1024, /// write buffer size + DbKeySize = 64, /// database max key size DbValueSize = 16384, /// database max value size DbTableSize = 1024, /// database table size @@ -77,9 +82,6 @@ enum _PersistenceConstantDef MaxConfKeyLengthCusName = 32, /// length of the config key custom name MaxRctLengthCustom_ID = 64, /// length of the customer ID - NSM_SHUTDOWN_TYPE_FAST = 2, /// Client registered for fast shutdown - NSM_SHUTDOWN_TYPE_NORMAL = 1, /// Client registered for normal shutdown - defaultMaxKeyValDataSize = 16384 /// default limit the key-value data size to 16kB }; @@ -115,19 +117,21 @@ extern const char* gUser; extern const char* gSeat; -/// path prefic for local cached database: /Data/mnt_c/<appId>/<database_name> +/// path prefix for local cached database: /Data/mnt_c/<appId>/<database_name> extern const char* gLocalCachePath; -/// path prefic for local write through database /Data/mnt_wt/<appId>/<database_name> +/// path prefix for local write through database /Data/mnt_wt/<appId>/<database_name> extern const char* gLocalWtPath; -/// path prefic for shared cached database: /Data/mnt_c/Shared/Group/<group_no>/<database_name> +/// path prefix for shared cached database: /Data/mnt_c/Shared/Group/<group_no>/<database_name> extern const char* gSharedCachePath; -/// path prefic for shared write through database: /Data/mnt_wt/Shared/Group/<group_no>/<database_name> +/// path prefix for shared write through database: /Data/mnt_wt/Shared/Group/<group_no>/<database_name> extern const char* gSharedWtPath; -/// path prefic for shared public cached database: /Data/mnt_c/Shared/Public//<database_name> +/// path prefix for shared public cached database: /Data/mnt_c/Shared/Public//<database_name> extern const char* gSharedPublicCachePath; -/// path prefic for shared public write through database: /Data/mnt_wt/Shared/Public/<database_name> +/// path prefix for shared public write through database: /Data/mnt_wt/Shared/Public/<database_name> extern const char* gSharedPublicWtPath; +/// path prefix for local cached files: /Data/mnt_c/<appId>/<user>/>userno>/<seat>/>seatno>/<resource> +extern const char* gLocalCacheFilePath; /// application id extern char gAppId[MaxAppNameLen]; @@ -136,6 +140,11 @@ extern char gAppId[MaxAppNameLen]; extern int gMaxKeyValDataSize; +/** + * @brief definition of change callback function + * + * @param pclNotification_s callback notification structure + */ extern int(* gChangeNotifyCallback)(pclNotification_s * notifyStruct); diff --git a/include_protected/persistence_client_library_db_access.h b/include_protected/persistence_client_library_db_access.h index a105ac2..feeb6c1 100644 --- a/include_protected/persistence_client_library_db_access.h +++ b/include_protected/persistence_client_library_db_access.h @@ -24,7 +24,7 @@ extern "C" { #endif -#define PERSIST_DATA_ACCESS_INTERFACE_VERSION (0x03000000U) +#define PERSIST_DATA_ACCESS_INTERFACE_VERSION (0x04010000U) #include "persistence_client_library_data_organization.h" @@ -122,6 +122,17 @@ int persistence_reg_notify_on_change(char* dbPath, char* key, unsigned int ldbid +/** + * @brief send a notification signal + * + * @param key the database key to register on + * @param context the database context + * @param reason the reason of the signal, values see pclNotifyStatus_e. + * + * @return 0 of registration was successfull; -1 if registration failes + */ +int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason); + //--------------------------------------------------------------------------------------------- // C U R S O R F U N C T I O N S //--------------------------------------------------------------------------------------------- diff --git a/include_protected/persistence_client_library_rc_table.h b/include_protected/persistence_client_library_rc_table.h index 813638f..77453f8 100644 --- a/include_protected/persistence_client_library_rc_table.h +++ b/include_protected/persistence_client_library_rc_table.h @@ -51,7 +51,7 @@ typedef enum _PersistenceStorage_e PersistenceStorage_custom = 2, /**< the data is managed over custom client implementation */ /** insert new entries here ... */ - PersistenceStoragePolicy_LastEntry /**< last entry */ + PersistenceStorage_LastEntry /**< last entry */ } PersistenceStorage_e; diff --git a/src/Makefile.am b/src/Makefile.am index fb737e5..060113a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,8 @@ endif include_HEADERS = ../include/persistence_client_library_key.h \ ../include/persistence_client_library_file.h \ - ../include/persistence_client_library_error_def.h + ../include/persistence_client_library_error_def.h \ + ../include/persistence_client_custom.h lib_LTLIBRARIES = libpersistence_client_library_common_data.la libpersistence_client_library.la @@ -38,7 +39,9 @@ libpersistence_client_library_la_SOURCES = \ persistence_client_library_custom_loader.c \ persistence_client_library_prct_access.c \ persistence_client_library_itzam_errors.c \ - crc32.c + persistence_client_library_backup_filelist.c \ + crc32.c \ + rbtree.c libpersistence_client_library_la_LDFLAGS = -export-dynamic $(LDFLAGS) -version-info $(PERS_CLIENT_LIBRARY_VERSION) diff --git a/src/persistence_client_library.c b/src/persistence_client_library.c index a720692..2fbae64 100644 --- a/src/persistence_client_library.c +++ b/src/persistence_client_library.c @@ -23,6 +23,7 @@ #include "persistence_client_library_dbus_service.h" #include "persistence_client_library_handle.h" #include "persistence_client_library_custom_loader.h" +#include "persistence_client_library_key.h" #include <string.h> #include <errno.h> @@ -41,21 +42,44 @@ extern char* __progname; /// debug log and trace (DLT) setup DLT_DECLARE_CONTEXT(persClientLibCtx); +/** + * @brief itialize client library + * + * @param shutdown mode NSM_SHUTDOWN_TYPE_FAST or NSM_SHUTDOWN_TYPE_NORMAL + * + */ +void pclInit(int shutdownMode); + + + +/** + * @brief deinitialize client library + * + * @param shutdown mode NSM_SHUTDOWN_TYPE_FAST or NSM_SHUTDOWN_TYPE_NORMAL + */ +void pclDeinit(int shutdownMode); -/// library constructor -void pers_library_init(void) __attribute__((constructor)); -/// library deconstructor -void pers_library_destroy(void) __attribute__((destructor)); +void pclLibraryConstructor(void) +{ + int shutdownReg = NSM_SHUTDOWN_TYPE_FAST | NSM_SHUTDOWN_TYPE_NORMAL; + pclInit(shutdownReg); +} + + +void pclLibraryDestructor(void) +{ + int shutdownReg = NSM_SHUTDOWN_TYPE_FAST | NSM_SHUTDOWN_TYPE_NORMAL; + pclDeinit(shutdownReg); +} -void pers_library_init(void) +void pclInit(int shutdownMode) { int status = 0; int i = 0; - int shutdownMode = NSM_SHUTDOWN_TYPE_NORMAL; DLT_REGISTER_APP("Persistence Client Library","persClientLib"); DLT_REGISTER_CONTEXT(persClientLibCtx,"persClientLib","Context for Logging"); @@ -136,9 +160,8 @@ void pers_library_init(void) -void pers_library_destroy(void) +void pclDeinit(int shutdownMode) { - int shutdownMode = NSM_SHUTDOWN_TYPE_NORMAL; #if ENABLE_DBUS_INTERFACE == 1 // unregister for lifecycle and persistence admin service dbus messages diff --git a/src/persistence_client_library_backup_filelist.c b/src/persistence_client_library_backup_filelist.c new file mode 100644 index 0000000..eae4425 --- /dev/null +++ b/src/persistence_client_library_backup_filelist.c @@ -0,0 +1,312 @@ +/****************************************************************************** + * Project Persistency + * (c) copyright 2012 + * Company XS Embedded GmbH + *****************************************************************************/ +/****************************************************************************** + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +******************************************************************************/ + /** + * @file persistence_client_library_backup_filelist.c + * @ingroup Persistence client library + * @author Ingo Huerner + * @brief Implementation of persistence client library backup filelist + * @see + */ + +#include "persistence_client_library_backup_filelist.h" +#include "rbtree.h" +#include "../include_protected/crc32.h" + + +#include <fcntl.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + + +/// structure definition for a key value item +typedef struct _key_value_s +{ + unsigned int key; + char* value; +}key_value_s; + + +void key_val_rel(void *p); + +void* key_val_dup(void *p); + +int key_val_cmp(const void *p1, const void *p2 ); + + + +/// the size of the token array +enum configConstants +{ + TOKENARRAYSIZE = 255 +}; + + +const char gCharLookup[] = +{ + 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) + 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 (?) + 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 (_) + 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 (~) + +}; + + +char* gpConfigFileMap = 0; +char* gpTokenArray[TOKENARRAYSIZE]; +int gTokenCounter = 0; +unsigned int gConfigFileSize = 0; + +/// the rb tree +static jsw_rbtree_t *gRb_tree_bl = NULL; + +void fillCharTokenArray() +{ + unsigned int i=0; + int blankCount=0; + char* tmpPointer = gpConfigFileMap; + + // set the first pointer to the start of the file + gpTokenArray[blankCount] = tmpPointer; + blankCount++; + + while(i < gConfigFileSize) + { + if(1 != gCharLookup[(int)*tmpPointer]) + { + *tmpPointer = 0; + + // check if we are at the end of the token array + if(blankCount >= TOKENARRAYSIZE) + { + break; + } + gpTokenArray[blankCount] = tmpPointer+1; + blankCount++; + gTokenCounter++; + + } + tmpPointer++; + i++; + } +} + + +void createAndStoreFileNames() +{ + int i= 0, j =0; + char path[128]; + const char* gFilePostFix = ".pers"; + const char* gKeyPathFormat = "/%s/%s/%s/%s/%s%s"; + key_value_s* item; + + // creat new tree + gRb_tree_bl = jsw_rbnew(key_val_cmp, key_val_dup, key_val_rel); + + if(gRb_tree_bl != NULL) + { + + for(i=0; i<128; i++) + { + // assemble path + snprintf(path, 128, gKeyPathFormat, gpTokenArray[j+2], // storage type + gpTokenArray[j+3], // policy id + gpTokenArray[j+4], // profileID + gpTokenArray[j], // application id + gpTokenArray[j+1], // filename + gFilePostFix); // file postfix + + // asign key and value to the rbtree item + item = malloc(sizeof(key_value_s)); + if(item != NULL) + { + item->key = crc32(0, (unsigned char*)path, strlen(path)); + // we don't need the path name here, we just need to know that this key is available in the tree + item->value = ""; + jsw_rbinsert(gRb_tree_bl, item); + free(item); + } + j+=5; + if(gpTokenArray[j] == NULL) + { + break; + } + } + } + +} + + +int readBlacklistConfigFile(const char* filename) +{ + int fd = 0, + status = 0; + struct stat buffer; + + memset(&buffer, 0, sizeof(buffer)); + status = stat(filename, &buffer); + if(status != -1) + { + gConfigFileSize = buffer.st_size; + } + + fd = open(filename, O_RDONLY); + if (fd == -1) + { + printf("configReader::readConfigFile ==> Error file open: %s | error: %s \n", filename, strerror(errno)); + + return -1; + } + + + // check for empty file + if(gConfigFileSize == 0) + { + printf("configReader::readConfigFile ==> Error file size is 0: %s | buffer.st_size: %d \n", filename, (int)buffer.st_size); + close(fd); + return -1; + } + + // map the config file into memory + gpConfigFileMap = (char*)mmap(0, gConfigFileSize, PROT_WRITE, MAP_PRIVATE, fd, 0); + + if (gpConfigFileMap == MAP_FAILED) + { + gpConfigFileMap = 0; + close(fd); + printf("configReader::readConfigFile ==> Error mapping the file: %s | error: %s \n", filename, strerror(errno)); + return -1; + } + + // reset the token counter + gTokenCounter = 0; + + fillCharTokenArray(); + + // create filernames and store them in the tree + createAndStoreFileNames(); + + munmap(gpConfigFileMap, gConfigFileSize); + + close(fd); + return 0; +} + + + +int need_backup_path(const char* path) +{ + return need_backup_key(crc32(0, (const unsigned char*)path, strlen(path))); +} + + + +int need_backup_key(unsigned int key) +{ + int rval = 1; + key_value_s* item = NULL; + key_value_s* foundItem = NULL; + + item = malloc(sizeof(key_value_s)); + if(item != NULL && gRb_tree_bl != NULL) + { + item->key = key; + foundItem = (key_value_s*)jsw_rbfind(gRb_tree_bl, item); + if(foundItem != NULL) + { + rval = 0; + } + free(item); + } + else + { + if(item!=NULL) + free(item); + + rval = -1; + printf("need_backup_key ==> item or gRb_tree_bl is NULL\n"); + } + + return rval; +} + + +/// compare function for tree key_value_s item +int key_val_cmp(const void *p1, const void *p2 ) +{ + int rval = -1; + key_value_s* first; + key_value_s* second; + + first = (key_value_s*)p1; + second = (key_value_s*)p2; + + if(second->key == first->key) + { + rval = 0; + } + else if(second->key < first->key) + { + rval = -1; + } + else + { + rval = 1; + } + + return rval; + } + +/// duplicate function for key_value_s item +void* key_val_dup(void *p) +{ + int value_size = 0; + key_value_s* src = NULL; + key_value_s* dst = NULL; + + src = (key_value_s*)p; + value_size = strlen(src->value)+1; + + // allocate memory for node + dst = malloc(sizeof(key_value_s)); + if(dst != NULL) + { + // duplicate hash key + dst->key = src->key; + + // duplicate value + dst->value = malloc(value_size); + if(dst->value != NULL) + strncpy(dst->value, src->value, value_size); + } + + + return dst; +} + +/// release function for key_value_s item +void key_val_rel(void *p ) +{ + key_value_s* rel = NULL; + rel = (key_value_s*)p; + + if(rel->value != NULL) + free(rel->value); + + if(rel != NULL) + free(rel); +} + + diff --git a/src/persistence_client_library_backup_filelist.h b/src/persistence_client_library_backup_filelist.h new file mode 100644 index 0000000..091a0fc --- /dev/null +++ b/src/persistence_client_library_backup_filelist.h @@ -0,0 +1,38 @@ +#ifndef PERSISTENCE_CLIENT_LIBRARY_BACKUP_FILELIST_H +#define PERSISTENCE_CLIENT_LIBRARY_BACKUP_FILELIST_H + +/****************************************************************************** + * Project Persistency + * (c) copyright 2013 + * Company XS Embedded GmbH + *****************************************************************************/ +/****************************************************************************** + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed + * with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +******************************************************************************/ + /** + * @file persistence_client_library_backup_filelist.h + * @ingroup Persistence client library + * @author Ingo Huerner + * @brief Header of the persistence client library backup file list + * @see + */ + + +/** + * @brief Read the blacklist configuration file + * + * @param filename the filename and path to the configuration fiel + * + * @return 1 success, 0 error + */ +int readBlacklistConfigFile(const char* filename); + + +int need_backup_key(unsigned int key); + + +int need_backup_path(const char* path); + +#endif /* PERS_BACKUP_BLACKLIST_H */ diff --git a/src/persistence_client_library_data_organization.c b/src/persistence_client_library_data_organization.c index 0dd5118..be18687 100644 --- a/src/persistence_client_library_data_organization.c +++ b/src/persistence_client_library_data_organization.c @@ -54,22 +54,25 @@ const char* gUser = "/user/"; const char* gSeat = "/seat/"; -/// path prefic for local cached database: /Data/mnt_c/<appId>/<database_name> +/// path prefix for local cached database: /Data/mnt_c/<appId>/<database_name> const char* gLocalCachePath = "/Data/mnt-c/%s%s"; -/// path prefic for local write through database /Data/mnt_wt/<appId>/<database_name> +/// path prefix for local write through database /Data/mnt_wt/<appId>/<database_name> const char* gLocalWtPath = "/Data/mnt-wt/%s%s"; -/// path prefic for shared cached database: /Data/mnt_c/Shared/Group/<group_no>/<database_name> +/// path prefix for shared cached database: /Data/mnt_c/Shared/Group/<group_no>/<database_name> const char* gSharedCachePath = "/Data/mnt-c/%s/Shared_Group_%x%s"; -/// path prefic for shared write through database: /Data/mnt_wt/Shared/Group/<group_no>/<database_name> +/// path prefix for shared write through database: /Data/mnt_wt/Shared/Group/<group_no>/<database_name> const char* gSharedWtPath = "/Data/mnt-wt/%s/Shared_Group_%x%s"; -/// path prefic for shared public cached database: /Data/mnt_c/Shared/Public//<database_name> +/// path prefix for shared public cached database: /Data/mnt_c/Shared/Public//<database_name> const char* gSharedPublicCachePath = "/Data/mnt-c/%s/Shared_Public%s"; -/// path prefic for shared public write through database: /Data/mnt_wt/Shared/Public/<database_name> +/// path prefix for shared public write through database: /Data/mnt_wt/Shared/Public/<database_name> const char* gSharedPublicWtPath = "/Data/mnt-wt/%s/Shared_Public%s"; +/// path prefix for local cached files: /Data/mnt_c/<appId>/<user>/<seat>/<resource> +const char* gLocalCacheFilePath = "/Data/mnt-c/%s/user/%d/seat/%d/%s"; + /// application id char gAppId[MaxAppNameLen]; diff --git a/src/persistence_client_library_db_access.c b/src/persistence_client_library_db_access.c index 10cd3d5..4185a7c 100644 --- a/src/persistence_client_library_db_access.c +++ b/src/persistence_client_library_db_access.c @@ -69,6 +69,10 @@ static itzam_btree gBtree[DbTableSize][PersistencePolicy_LastEntry]; static int gBtreeCreated[DbTableSize][PersistencePolicy_LastEntry] = { {0} }; +// function prototype +int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, unsigned int reason); + + itzam_btree* pers_db_open(PersistenceInfo_s* info, const char* dbPath) { int arrayIdx = 0; @@ -199,12 +203,12 @@ int pers_db_read_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned char workaroundPath[128]; // workaround, because /sys/ can not be accessed on host!!!! snprintf(workaroundPath, 128, "%s%s", "/Data", dbPath ); - if( (idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) ) + if( (idx < PersCustomLib_LastEntry) && (*gPersCustomFuncs[idx].custom_plugin_handle_get_data != NULL) ) { if(info->configKey.customID[0] == '\0') // if we have not a customID we use the key - gPersCustomFuncs[idx].custom_plugin_get_data(key, (char*)buffer, buffer_size); + read_size = gPersCustomFuncs[idx].custom_plugin_get_data(key, (char*)buffer, buffer_size); else - gPersCustomFuncs[idx].custom_plugin_get_data(info->configKey.customID, (char*)buffer, buffer_size); + read_size = gPersCustomFuncs[idx].custom_plugin_get_data(info->configKey.customID, (char*)buffer, buffer_size); } else { @@ -273,42 +277,7 @@ int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned if(PersistenceStorage_shared == info->configKey.storage) { - // send changed notification - DBusMessage* message; - char ldbid_array[12]; - char user_array[12]; - char seat_array[12]; - const char* ldbid_ptr = ldbid_array; - const char* user_ptr = user_array; - const char* seat_ptr = seat_array; - - memset(ldbid_array, 0, 12); - memset(user_array, 0, 12); - memset(seat_array, 0, 12); - - // dbus_bus_add_match is used for the notification mechanism, - // and this works only for type DBUS_TYPE_STRING as message arguments - // this is the reason to use string instead of integer types directly - snprintf(ldbid_array, 12, "%d", info->context.ldbid); - snprintf(user_array, 12, "%d", info->context.user_no); - snprintf(seat_array, 12, "%d", info->context.seat_no); - - message = dbus_message_new_signal("/org/genivi/persistence/adminconsumer", // const char *path, - "org.genivi.persistence.adminconsumer", // const char *interface, - "PersistenceValueChanged" ); // const char *name - - dbus_message_append_args(message, - DBUS_TYPE_STRING, &key, - DBUS_TYPE_STRING, &ldbid_ptr, - DBUS_TYPE_STRING, &user_ptr, - DBUS_TYPE_STRING, &seat_ptr, - DBUS_TYPE_INVALID); - - // Send the signal - dbus_connection_send(get_dbus_connection(), message, NULL); - - // Free the signal now we have finished with it - dbus_message_unref(message); + pers_send_Notification_Signal(key, &info->context, pclNotifyStatus_deleted); } } else @@ -332,12 +301,12 @@ int pers_db_write_key(char* dbPath, char* key, PersistenceInfo_s* info, unsigned else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library { int idx = custom_client_name_to_id(dbPath, 1); - if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) ) + if((idx < PersCustomLib_LastEntry) && (*gPersCustomFuncs[idx].custom_plugin_handle_set_data != NULL) ) { if(info->configKey.customID[0] == '\0') // if we have not a customID we use the key - gPersCustomFuncs[idx].custom_plugin_set_data(key, (char*)buffer, buffer_size); + write_size = gPersCustomFuncs[idx].custom_plugin_set_data(key, (char*)buffer, buffer_size); else - gPersCustomFuncs[idx].custom_plugin_set_data(info->configKey.customID, (char*)buffer, buffer_size); + write_size = gPersCustomFuncs[idx].custom_plugin_set_data(info->configKey.customID, (char*)buffer, buffer_size); } else { @@ -393,12 +362,12 @@ int pers_db_get_key_size(char* dbPath, char* key, PersistenceInfo_s* info) else if(PersistenceStorage_custom == info->configKey.storage) // custom storage implementation via custom library { int idx = custom_client_name_to_id(dbPath, 1); - if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) ) + if((idx < PersCustomLib_LastEntry) && (*gPersCustomFuncs[idx].custom_plugin_handle_set_data != NULL) ) { if(info->configKey.customID[0] == '\0') // if we have not a customID we use the key - gPersCustomFuncs[idx].custom_plugin_get_size(key); + read_size = gPersCustomFuncs[idx].custom_plugin_get_size(key); else - gPersCustomFuncs[idx].custom_plugin_get_size(info->configKey.customID); + read_size = gPersCustomFuncs[idx].custom_plugin_get_size(info->configKey.customID); } else { @@ -443,6 +412,11 @@ int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info) itzam_btree_transaction_commit(btree); // transaction end // ----------------------------------------------------------------------------- + + if(PersistenceStorage_shared == info->configKey.storage) + { + pers_send_Notification_Signal(dbKey, &info->context, pclNotifyStatus_changed); + } } else { @@ -459,12 +433,12 @@ int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info) else // custom storage implementation via custom library { int idx = custom_client_name_to_id(dbPath, 1); - if((idx < PersCustomLib_LastEntry) && (gPersCustomFuncs[idx].custom_plugin_handle_set_data) ) + if((idx < PersCustomLib_LastEntry) && (*gPersCustomFuncs[idx].custom_plugin_handle_set_data != NULL) ) { if(info->configKey.customID[0] == '\0') // if we have not a customID we use the key - gPersCustomFuncs[idx].custom_plugin_delete_data(dbKey); + ret = gPersCustomFuncs[idx].custom_plugin_delete_data(dbKey); else - gPersCustomFuncs[idx].custom_plugin_delete_data(info->configKey.customID); + ret = gPersCustomFuncs[idx].custom_plugin_delete_data(info->configKey.customID); } else { @@ -478,36 +452,120 @@ int pers_db_delete_key(char* dbPath, char* dbKey, PersistenceInfo_s* info) int persistence_reg_notify_on_change(char* dbPath, char* key, unsigned int ldbid, unsigned int user_no, unsigned int seat_no, pclChangeNotifyCallback_t callback) { - int rval = -1; + int rval = 0; DBusError error; dbus_error_init (&error); - char rule[300]; - char ldbid_array[12]; - char user_array[12]; - char seat_array[12]; - - memset(ldbid_array, 0, 12); - memset(user_array, 0, 12); - memset(seat_array, 0, 12); + char ruleChanged[DbusMatchRuleSize]; + char ruleDeleted[DbusMatchRuleSize]; // assign callback gChangeNotifyCallback = callback; - // dbus_bus_add_match works only for type DBUS_TYPE_STRING as message arguments - // this is the reason to use string instead of integer types directly - snprintf(ldbid_array, 12, "%u", ldbid); - snprintf(user_array, 12, "%u", user_no); - snprintf(seat_array, 12, "%u", seat_no); + // add match for c h a n g e + snprintf(ruleChanged, DbusMatchRuleSize, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResChange',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'", + key, ldbid, user_no, seat_no); + dbus_bus_add_match(get_dbus_connection(), ruleChanged, &error); + - snprintf(rule, 256, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceValueChanged',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%s',arg2='%s',arg3='%s'", - key, ldbid_array, user_array, seat_array); + // add match for d e l e t e + snprintf(ruleDeleted, DbusMatchRuleSize, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResDelete',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'", + key, ldbid, user_no, seat_no); + dbus_bus_add_match(get_dbus_connection(), ruleDeleted, &error); - dbus_bus_add_match(get_dbus_connection(), rule, &error); + + // add match for c r e a t e + snprintf(ruleDeleted, DbusMatchRuleSize, "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResCreate',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'", + key, ldbid, user_no, seat_no); + dbus_bus_add_match(get_dbus_connection(), ruleDeleted, &error); return rval; } +int pers_send_Notification_Signal(const char* key, PersistenceDbContext_s* context, pclNotifyStatus_e reason) +{ + DBusMessage* message; + dbus_bool_t ret; + int rval = 0; + char ldbid_array[DbusSubMatchSize]; + char user_array[DbusSubMatchSize]; + char seat_array[DbusSubMatchSize]; + const char* ldbid_ptr = ldbid_array; + const char* user_ptr = user_array; + const char* seat_ptr = seat_array; + + char* changeSignal = "PersistenceResChange"; + char* deleteSignal = "PersistenceResDelete"; + char* createSignal = "PersistenceResCreate"; + char* theReason = NULL; + + memset(ldbid_array, 0, DbusSubMatchSize); + memset(user_array, 0, DbusSubMatchSize); + memset(seat_array, 0, DbusSubMatchSize); + + + // dbus_bus_add_match is used for the notification mechanism, + // and this works only for type DBUS_TYPE_STRING as message arguments + // this is the reason to use string instead of integer types directly + snprintf(ldbid_array, DbusSubMatchSize, "%d", context->ldbid); + snprintf(user_array, DbusSubMatchSize, "%d", context->user_no); + snprintf(seat_array, DbusSubMatchSize, "%d", context->seat_no); + + switch(reason) + { + case pclNotifyStatus_deleted: + theReason = deleteSignal; + break; + case pclNotifyStatus_created: + theReason = createSignal; + break; + case pclNotifyStatus_changed: + theReason = changeSignal; + break; + default: + theReason = changeSignal; + break; + } + + if(theReason != NULL) + { + message = dbus_message_new_signal("/org/genivi/persistence/adminconsumer", // const char *path, + "org.genivi.persistence.adminconsumer", // const char *interface, + theReason); // const char *name + + ret = dbus_message_append_args(message, + DBUS_TYPE_STRING, &key, + DBUS_TYPE_STRING, &ldbid_ptr, + DBUS_TYPE_STRING, &user_ptr, + DBUS_TYPE_STRING, &seat_ptr, + DBUS_TYPE_INVALID); + if(ret == TRUE) + { + // Send the signal + if(dbus_connection_send(get_dbus_connection(), message, NULL) == TRUE) + { + // Free the signal now we have finished with it + dbus_message_unref(message); + } + else + { + rval = EPERS_NOTIFY_SIG; + } + } + else + { + printf("pers_send_Notification_Signal: \n"); + rval = EPERS_NOTIFY_SIG; + } + } + else + { + rval = EPERS_NOTIFY_SIG; + } + + return rval; +} + //--------------------------------------------------------------------------------------------------------- // C U R S O R F U N C T I O N S diff --git a/src/persistence_client_library_dbus_service.c b/src/persistence_client_library_dbus_service.c index 8a1374c..05804d7 100644 --- a/src/persistence_client_library_dbus_service.c +++ b/src/persistence_client_library_dbus_service.c @@ -129,7 +129,26 @@ static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connec printf("checkPersAdminconsumerSignalInterface '%s' -> '%s'\n", dbus_message_get_interface(message), dbus_message_get_member(message)); if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) { - if((0==strcmp("PersistenceValueChanged", dbus_message_get_member(message)))) + pclNotification_s notifyStruct; + int validMessage = 0; + + if((0==strcmp("PersistenceResChange", dbus_message_get_member(message)))) + { + notifyStruct.pclKeyNotify_Status = pclNotifyStatus_changed; + validMessage = 1; + } + else if((0==strcmp("PersistenceResDelete", dbus_message_get_member(message)))) + { + notifyStruct.pclKeyNotify_Status = pclNotifyStatus_deleted; + validMessage = 1; + } + else if((0==strcmp("PersistenceRes", dbus_message_get_member(message)))) + { + notifyStruct.pclKeyNotify_Status = pclNotifyStatus_created; + validMessage = 1; + } + + if(validMessage == 1) { DBusError error; DBusMessage *reply; @@ -138,11 +157,6 @@ static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connec char* user_no; char* seat_no; - printf("PersistenceValueChanged signal\n"); - // to do handle signal - pclNotification_s notifyStruct; - notifyStruct.pclKeyNotify_Status = pclNotifyStatus_changed; - if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, ¬ifyStruct.resource_id, DBUS_TYPE_STRING, &ldbid, DBUS_TYPE_STRING, &user_no, diff --git a/src/persistence_client_library_file.c b/src/persistence_client_library_file.c index 6c65d00..fad6265 100644 --- a/src/persistence_client_library_file.c +++ b/src/persistence_client_library_file.c @@ -37,13 +37,18 @@ // header prototype definition of internal functions -int pcl_create_backup(const char* srcPath, int srcfd, const char* csumPath, const char* csumBuf); +int pclCreateFile(const char* path); -int pcl_recover_from_backup(int backupFd, const char* original); +int pclCreateBackup(const char* srcPath, int srcfd, const char* csumPath, const char* csumBuf); -int pcl_calc_crc32_checksum(int fd, char crc32sum[]); +int pclRecoverFromBackup(int backupFd, const char* original); + +int pclCalcCrc32Csum(int fd, char crc32sum[]); + +int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags); + +int pclBackupNeeded(const char* path); -int pcl_verify_consistency(const char* origPath, const char* backupPath, const char* csumPath, int flags); //------------------------------------------------------------- @@ -58,10 +63,16 @@ int pclFileClose(int fd) if( gFileHandleArray[fd].permission != PersistencePermission_ReadOnly) { // remove bakup file - rval = remove(gFileHandleArray[fd].backupPath ); + if(remove(gFileHandleArray[fd].backupPath ) == -1) + { + printf("pclFileClose ==> failed to remove backup file\n"); + } // remove checksum file - rval = remove(gFileHandleArray[fd].csumPath); + if(remove(gFileHandleArray[fd].csumPath) == -1) + { + printf("pclFileClose ==> failed to remove checksum file\n"); + } } __sync_fetch_and_sub(&gOpenFdArray[fd], FileClosed); // set closed flag rval = close(fd); @@ -111,8 +122,10 @@ int pclFileOpen(unsigned int ldbid, const char* resource_id, unsigned int user_n int handle = -1, shared_DB = 0; PersistenceInfo_s dbContext; - char dbKey[DbKeyMaxLen]; // database key - char dbPath[DbPathMaxLen]; // database location + char dbKey[DbKeyMaxLen]; // database key + char dbPath[DbPathMaxLen]; // database location + char backupPath[DbKeyMaxLen]; // backup file + char csumPath[DbPathMaxLen]; // checksum file memset(dbKey, 0, DbKeyMaxLen); memset(dbPath, 0, DbPathMaxLen); @@ -128,19 +141,18 @@ int pclFileOpen(unsigned int ldbid, const char* resource_id, unsigned int user_n && (dbContext.configKey.type == PersistenceResourceType_file) ) // check if type matches { int flags = dbContext.configKey.permission; - char backupPath[DbKeyMaxLen]; // backup file - char csumPath[DbPathMaxLen]; // checksum file - - memset(backupPath, 0, DbKeyMaxLen); - memset(csumPath, 0, DbPathMaxLen); // file will be opend writable, so check about data consistency - if(dbContext.configKey.permission != PersistencePermission_ReadOnly) + if( dbContext.configKey.permission != PersistencePermission_ReadOnly + && pclBackupNeeded(dbPath) ) { + memset(backupPath, 0, DbKeyMaxLen); + memset(csumPath, 0, DbPathMaxLen); + snprintf(backupPath, DbPathMaxLen, "%s%s", dbPath, "~"); snprintf(csumPath, DbPathMaxLen, "%s%s", dbPath, "~.crc"); - if((handle = pcl_verify_consistency(dbPath, backupPath, csumPath, flags)) == -1) + if((handle = pclVerifyConsistency(dbPath, backupPath, csumPath, flags)) == -1) { printf("pclFileOpen: error => file inconsistent, recovery N O T possible!\n"); return -1; @@ -160,6 +172,7 @@ int pclFileOpen(unsigned int ldbid, const char* resource_id, unsigned int user_n { strcpy(gFileHandleArray[handle].backupPath, backupPath); strcpy(gFileHandleArray[handle].csumPath, csumPath); + gFileHandleArray[handle].backupCreated = 0; gFileHandleArray[handle].permission = dbContext.configKey.permission; } @@ -172,70 +185,38 @@ int pclFileOpen(unsigned int ldbid, const char* resource_id, unsigned int user_n } else // file does not exist, create file and folder { - const char* delimiters = "/\n"; // search for blank and end of line - char* tokenArray[24]; - char* thePath = dbPath; - char createPath[DbPathMaxLen]; - int numTokens = 0, i = 0, validPath = 1; - - tokenArray[numTokens++] = strtok(thePath, delimiters); - while(tokenArray[numTokens-1] != NULL ) - { - tokenArray[numTokens] = strtok(NULL, delimiters); - if(tokenArray[numTokens] != NULL) - { - numTokens++; - if(numTokens >= 24) - { - validPath = 0; - break; - } - } - else - { - break; - } - } + handle = pclCreateFile(dbPath); + } + } + else + { + // assemble file string for local cached location + snprintf(dbPath, DbPathMaxLen, gLocalCacheFilePath, gAppId, user_no, seat_no, resource_id); + handle = pclCreateFile(dbPath); - if(validPath == 1) + if(handle != -1) + { + if(handle < MaxPersHandle) { - memset(createPath, 0, DbPathMaxLen); - snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] ); - for(i=1; i<numTokens-1; i++) - { - // create folders - strncat(createPath, "/", DbPathMaxLen-1); - strncat(createPath, tokenArray[i], DbPathMaxLen-1); - mkdir(createPath, 0744); - } - // finally create the file - strncat(createPath, "/", DbPathMaxLen-1); - strncat(createPath, tokenArray[i], DbPathMaxLen-1); - handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); - if(handle != -1) - { - if(handle < MaxPersHandle) - { - __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag - } - else - { - close(handle); - handle = EPERS_MAXHANDLE; - } - } + memset(backupPath, 0, DbKeyMaxLen); + memset(csumPath, 0, DbPathMaxLen); + + snprintf(backupPath, DbPathMaxLen, "%s%s", dbPath, "~"); + snprintf(csumPath, DbPathMaxLen, "%s%s", dbPath, "~.crc"); + + __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag + strcpy(gFileHandleArray[handle].backupPath, backupPath); + strcpy(gFileHandleArray[handle].csumPath, csumPath); + gFileHandleArray[handle].backupCreated = 0; + gFileHandleArray[handle].permission = PersistencePermission_ReadWrite; // make it writable } else { - printf("pclFileOpen ==> no valid path to create: %s\n", dbPath); + close(handle); + handle = EPERS_MAXHANDLE; } } } - else - { - handle = shared_DB; - printf("pclFileOpen ==> no valid database context or resource no file\n"); - } return handle; } @@ -344,14 +325,14 @@ int pclFileWriteData(int fd, const void * buffer, int buffer_size) if( gFileHandleArray[fd].permission != PersistencePermission_ReadOnly && gFileHandleArray[fd].backupCreated == 0) { - char csumBuf[64]; - memset(csumBuf, 0, 64); + char csumBuf[ChecksumBufSize]; + memset(csumBuf, 0, ChecksumBufSize); // calculate checksum - pcl_calc_crc32_checksum(fd, csumBuf); + pclCalcCrc32Csum(fd, csumBuf); // create checksum and backup file - pcl_create_backup(gFileHandleArray[fd].backupPath, fd, gFileHandleArray[fd].csumPath, csumBuf); + pclCreateBackup(gFileHandleArray[fd].backupPath, fd, gFileHandleArray[fd].csumPath, csumBuf); gFileHandleArray[fd].backupCreated = 1; } @@ -373,19 +354,84 @@ int pclFileWriteData(int fd, const void * buffer, int buffer_size) * Functions to create backup files ****************************************************************************************/ -int pcl_verify_consistency(const char* origPath, const char* backupPath, const char* csumPath, int flags) +int pclCreateFile(const char* path) +{ + const char* delimiters = "/\n"; // search for blank and end of line + char* tokenArray[24]; + char* thePath = (char*)path; + char createPath[DbPathMaxLen]; + int numTokens = 0, i = 0, validPath = 1; + int handle = 0; + + tokenArray[numTokens++] = strtok(thePath, delimiters); + while(tokenArray[numTokens-1] != NULL ) + { + tokenArray[numTokens] = strtok(NULL, delimiters); + if(tokenArray[numTokens] != NULL) + { + numTokens++; + if(numTokens >= 24) + { + validPath = 0; + break; + } + } + else + { + break; + } + } + + if(validPath == 1) + { + memset(createPath, 0, DbPathMaxLen); + snprintf(createPath, DbPathMaxLen, "/%s",tokenArray[0] ); + for(i=1; i<numTokens-1; i++) + { + // create folders + strncat(createPath, "/", DbPathMaxLen-1); + strncat(createPath, tokenArray[i], DbPathMaxLen-1); + mkdir(createPath, 0744); + } + // finally create the file + strncat(createPath, "/", DbPathMaxLen-1); + strncat(createPath, tokenArray[i], DbPathMaxLen-1); + handle = open(createPath, O_CREAT|O_RDWR |O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + if(handle != -1) + { + if(handle < MaxPersHandle) + { + __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag + } + else + { + close(handle); + handle = EPERS_MAXHANDLE; + } + } + } + else + { + printf("pclCreatePathAndFile ==> no valid path to create: %s\n", path); + } + + return handle; +} + + +int pclVerifyConsistency(const char* origPath, const char* backupPath, const char* csumPath, int openFlags) { int handle = 0, readSize = 0; int backupAvail = 0, csumAvail = 0; int fdCsum = 0, fdBackup = 0; - char origCsumBuf[64]; - char backCsumBuf[64]; - char csumBuf[64]; + char origCsumBuf[ChecksumBufSize]; + char backCsumBuf[ChecksumBufSize]; + char csumBuf[ChecksumBufSize]; - memset(origCsumBuf, 0, 64); - memset(backCsumBuf, 0, 64); - memset(csumBuf, 0, 64); + memset(origCsumBuf, 0, ChecksumBufSize); + memset(backCsumBuf, 0, ChecksumBufSize); + memset(csumBuf, 0, ChecksumBufSize); // check if we have a backup and checksum file backupAvail = access(backupPath, F_OK); @@ -403,26 +449,26 @@ int pcl_verify_consistency(const char* origPath, const char* backupPath, const c fdBackup = open(backupPath, O_RDONLY); if(fdBackup != -1) { - pcl_calc_crc32_checksum(fdBackup, backCsumBuf); + pclCalcCrc32Csum(fdBackup, backCsumBuf); fdCsum = open(csumPath, O_RDONLY); if(fdCsum != -1) { - readSize = read(fdCsum, csumBuf, 64); + readSize = read(fdCsum, csumBuf, ChecksumBufSize); if(readSize > 0) { if(strcmp(csumBuf, backCsumBuf) == 0) { // checksum matches ==> replace with original file - handle = pcl_recover_from_backup(fdBackup, origPath); + handle = pclRecoverFromBackup(fdBackup, origPath); } else { // checksum does not match, check checksum with original file - handle = open(origPath, flags); + handle = open(origPath, openFlags); if(handle != -1) { - pcl_calc_crc32_checksum(handle, origCsumBuf); + pclCalcCrc32Csum(handle, origCsumBuf); if(strcmp(csumBuf, origCsumBuf) != 0) { close(handle); @@ -466,18 +512,18 @@ int pcl_verify_consistency(const char* origPath, const char* backupPath, const c fdCsum = open(csumPath, O_RDONLY); if(fdCsum != -1) { - readSize = read(fdCsum, csumBuf, 64); - if(readSize != 64) + readSize = read(fdCsum, csumBuf, ChecksumBufSize); + if(readSize != ChecksumBufSize) { printf("verifyConsistency ==> read checksum: invalid readSize\n"); } close(fdCsum); // calculate the checksum form the original file to see if it matches - handle = open(origPath, flags); + handle = open(origPath, openFlags); if(handle != -1) { - pcl_calc_crc32_checksum(handle, origCsumBuf); + pclCalcCrc32Csum(handle, origCsumBuf); if(strcmp(csumBuf, origCsumBuf) != 0) { @@ -508,14 +554,14 @@ int pcl_verify_consistency(const char* origPath, const char* backupPath, const c fdBackup = open(backupPath, O_RDONLY); if(fdBackup != -1) { - pcl_calc_crc32_checksum(fdBackup, backCsumBuf); + pclCalcCrc32Csum(fdBackup, backCsumBuf); close(fdBackup); // calculate the checksum form the original file to see if it matches - handle = open(origPath, flags); + handle = open(origPath, openFlags); if(handle != -1) { - pcl_calc_crc32_checksum(handle, origCsumBuf); + pclCalcCrc32Csum(handle, origCsumBuf); if(strcmp(backCsumBuf, origCsumBuf) != 0) { @@ -552,17 +598,17 @@ int pcl_verify_consistency(const char* origPath, const char* backupPath, const c } -int pcl_recover_from_backup(int backupFd, const char* original) +int pclRecoverFromBackup(int backupFd, const char* original) { int handle = 0; int readSize = 0; - char buffer[1024]; + char buffer[RDRWBufferSize]; handle = open(original, O_TRUNC | O_RDWR); if(handle != -1) { // copy data from one file to another - while((readSize = read(backupFd, buffer, 1024)) > 0) + while((readSize = read(backupFd, buffer, RDRWBufferSize)) > 0) { if(write(handle, buffer, readSize) != readSize) { @@ -576,11 +622,11 @@ int pcl_recover_from_backup(int backupFd, const char* original) return handle; } -int pcl_create_backup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf) +int pclCreateBackup(const char* dstPath, int srcfd, const char* csumPath, const char* csumBuf) { int dstFd = 0, csfd = 0; int readSize = -1; - char buffer[1024]; + char buffer[RDRWBufferSize]; // create checksum file and and write checksum //printf(" pcl_create_backu => create checksum file: %s \n", csumPath); @@ -610,7 +656,7 @@ int pcl_create_backup(const char* dstPath, int srcfd, const char* csumPath, cons curPos = lseek(srcfd, 0, SEEK_CUR); // copy data from one file to another - while((readSize = read(srcfd, buffer, 1024)) > 0) + while((readSize = read(srcfd, buffer, RDRWBufferSize)) > 0) { if(write(dstFd, buffer, readSize) != readSize) { @@ -638,7 +684,7 @@ int pcl_create_backup(const char* dstPath, int srcfd, const char* csumPath, cons -int pcl_calc_crc32_checksum(int fd, char crc32sum[]) +int pclCalcCrc32Csum(int fd, char crc32sum[]) { int rval = 1; @@ -680,4 +726,14 @@ int pcl_calc_crc32_checksum(int fd, char crc32sum[]) +int pclBackupNeeded(const char* path) +{ + int needBackup = 1; + + + return needBackup; +} + + + diff --git a/src/persistence_client_library_key.c b/src/persistence_client_library_key.c index 1469d72..0256173 100644 --- a/src/persistence_client_library_key.c +++ b/src/persistence_client_library_key.c @@ -55,7 +55,7 @@ int pclKeyHandleOpen(unsigned int ldbid, const char* resource_id, unsigned int u if( (handle >= 0) && (dbContext.configKey.type == PersistenceResourceType_key) ) // check if type matches { - if(dbContext.configKey.storage < PersistenceStoragePolicy_LastEntry) // check if store policy is valid + if(dbContext.configKey.storage < PersistenceStorage_LastEntry) // check if store policy is valid { if(PersistenceStorage_custom == dbContext.configKey.storage) { @@ -211,7 +211,7 @@ int pclKeyHandleRegisterNotifyOnChange(int key_handle, pclChangeNotifyCallback_t if(key_handle < MaxPersHandle) { - pclKeyRegisterNotifyOnChange(gKeyHandleArray[key_handle].info.context.ldbid, + rval = pclKeyRegisterNotifyOnChange(gKeyHandleArray[key_handle].info.context.ldbid, gKeyHandleArray[key_handle].resourceID, gKeyHandleArray[key_handle].info.context.user_no, gKeyHandleArray[key_handle].info.context.seat_no, callback); @@ -302,7 +302,7 @@ int pclKeyDelete(unsigned int ldbid, const char* resource_id, unsigned int user_ if( (rval >= 0) && (dbContext.configKey.type == PersistenceResourceType_key) ) // check if type is matching { - if( dbContext.configKey.storage < PersistenceStoragePolicy_LastEntry + if( dbContext.configKey.storage < PersistenceStorage_LastEntry && dbContext.configKey.storage >= PersistenceStorage_local) // check if store policy is valid { rval = pers_db_delete_key(dbPath, dbKey, &dbContext); @@ -344,7 +344,7 @@ int pclKeyGetSize(unsigned int ldbid, const char* resource_id, unsigned int user if( (data_size >= 0) && (dbContext.configKey.type == PersistenceResourceType_key) ) // check if type matches { - if( dbContext.configKey.storage < PersistenceStoragePolicy_LastEntry + if( dbContext.configKey.storage < PersistenceStorage_LastEntry && dbContext.configKey.storage >= PersistenceStorage_local) // check if store policy is valid { data_size = pers_db_get_key_size(dbPath, dbKey, &dbContext); @@ -390,7 +390,7 @@ int pclKeyReadData(unsigned int ldbid, const char* resource_id, unsigned int use && (dbContext.configKey.type == PersistenceResourceType_key) ) { - if( dbContext.configKey.storage < PersistenceStoragePolicy_LastEntry + if( dbContext.configKey.storage < PersistenceStorage_LastEntry && dbContext.configKey.storage >= PersistenceStorage_local) // check if store policy is valid { data_size = pers_db_read_key(dbPath, dbKey, &dbContext, buffer, buffer_size); @@ -447,7 +447,7 @@ int pclKeyWriteData(unsigned int ldbid, const char* resource_id, unsigned int us hash_val_data = crc32(hash_val_data, buffer, buffer_size); // store data - if( dbContext.configKey.storage < PersistenceStoragePolicy_LastEntry + if( dbContext.configKey.storage < PersistenceStorage_LastEntry && dbContext.configKey.storage >= PersistenceStorage_local) // check if store policy is valid { data_size = pers_db_write_key(dbPath, dbKey, &dbContext, buffer, buffer_size); @@ -505,6 +505,7 @@ int pclKeyRegisterNotifyOnChange(unsigned int ldbid, const char* resource_id, un else { printf("pclKeyRegisterNotifyOnChange: error - resource is not a shared resource or resource is not a key\n"); + rval = EPERS_RES_NO_KEY; } return rval; diff --git a/src/persistence_client_library_prct_access.c b/src/persistence_client_library_prct_access.c index a1ba5bf..96b6f69 100644 --- a/src/persistence_client_library_prct_access.c +++ b/src/persistence_client_library_prct_access.c @@ -20,6 +20,7 @@ #include "persistence_client_library_prct_access.h" #include "persistence_client_library_itzam_errors.h" +#include "../include_protected/persistence_client_library_db_access.h" #include <stdlib.h> @@ -201,6 +202,9 @@ int get_db_context(PersistenceInfo_s* dbContext, const char* resource_id, unsign memcpy(dbContext->configKey.custom_name, "default", strlen("default")); //printf("get_db_context ==> R E S O U R C E N O T found: %s \n", resource_id); + // send create notification + rval = pers_send_Notification_Signal(dbKey, &dbContext->context, pclNotifyStatus_created); + rval = get_db_path_and_key(dbContext, resource_id, dbKey, dbPath); } @@ -212,7 +216,7 @@ int get_db_context(PersistenceInfo_s* dbContext, const char* resource_id, unsign // status: OK int get_db_path_and_key(PersistenceInfo_s* dbContext, const char* resource_id, char dbKey[], char dbPath[]) { - int storePolicy = PersistenceStoragePolicy_LastEntry; + int storePolicy = PersistenceStorage_LastEntry; // // create resource database key diff --git a/src/rbtree.c b/src/rbtree.c new file mode 100644 index 0000000..6a20221 --- /dev/null +++ b/src/rbtree.c @@ -0,0 +1,635 @@ +/****************************************************************************** + * Project Persistency + * (c) copyright 2012 + * Company XS Embedded GmbH + *****************************************************************************/ +/****************************************************************************** + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + /** + * @file pers_rbtree.c + * @ingroup Persistence device access layer + * @author Ingo Huerner + * @brief Implementation of rbtree functions + * @see + */ + +/* + Red Black balanced tree library + + > Created (Julienne Walker): August 23, 2003 + > Modified (Julienne Walker): March 14, 2008 +*/ + + +#include "rbtree.h" +#include <stdio.h> + + +#ifdef __cplusplus +#include <cstdlib> + +using std::malloc; +using std::free; +using std::size_t; +#else +#include <stdlib.h> +#endif + +#ifndef HEIGHT_LIMIT +#define HEIGHT_LIMIT 256 /* Tallest allowable tree */ +#endif + + +typedef struct jsw_rbnode { + int red; /* Color (1=red, 0=black) */ + void *data; /* User-defined content */ + struct jsw_rbnode *link[2]; /* Left (0) and right (1) links */ +} jsw_rbnode_t; + +struct jsw_rbtree { + jsw_rbnode_t *root; /* Top of the tree */ + cmp_f cmp; /* Compare two items */ + dup_f dup; /* Clone an item (user-defined) */ + rel_f rel; /* Destroy an item (user-defined) */ + size_t size; /* Number of items (user-defined) */ +}; + +struct jsw_rbtrav { + jsw_rbtree_t *tree; /* Paired tree */ + jsw_rbnode_t *it; /* Current node */ + jsw_rbnode_t *path[HEIGHT_LIMIT]; /* Traversal path */ + size_t top; /* Top of stack */ +}; + +/** + <summary> + Checks the color of a red black node + <summary> + <param name="root">The node to check</param> + <returns>1 for a red node, 0 for a black node</returns> + <remarks>For jsw_rbtree.c internal use only</remarks> +*/ +static int is_red ( jsw_rbnode_t *root ) +{ + return root != NULL && root->red == 1; +} + +/** + <summary> + Performs a single red black rotation in the specified direction + This function assumes that all nodes are valid for a rotation + <summary> + <param name="root">The original root to rotate around</param> + <param name="dir">The direction to rotate (0 = left, 1 = right)</param> + <returns>The new root ater rotation</returns> + <remarks>For jsw_rbtree.c internal use only</remarks> +*/ +static jsw_rbnode_t *jsw_single ( jsw_rbnode_t *root, int dir ) +{ + jsw_rbnode_t *save = NULL; + + if(root != NULL) + { + save = root->link[!dir]; + + root->link[!dir] = save->link[dir]; + save->link[dir] = root; + + root->red = 1; + save->red = 0; + } + + return save; +} + +/** + <summary> + Performs a double red black rotation in the specified direction + This function assumes that all nodes are valid for a rotation + <summary> + <param name="root">The original root to rotate around</param> + <param name="dir">The direction to rotate (0 = left, 1 = right)</param> + <returns>The new root after rotation</returns> + <remarks>For jsw_rbtree.c internal use only</remarks> +*/ +static jsw_rbnode_t *jsw_double ( jsw_rbnode_t *root, int dir ) +{ + root->link[!dir] = jsw_single ( root->link[!dir], !dir ); + + return jsw_single ( root, dir ); +} + +/** + <summary> + Creates an initializes a new red black node with a copy of + the data. This function does not insert the new node into a tree + <summary> + <param name="tree">The red black tree this node is being created for</param> + <param name="data">The data value that will be stored in this node</param> + <returns>A pointer to the new node</returns> + <remarks> + For jsw_rbtree.c internal use only. The data for this node must + be freed using the same tree's rel function. The returned pointer + must be freed using C's free function + </remarks> +*/ +static jsw_rbnode_t *new_node ( jsw_rbtree_t *tree, void *data ) +{ + jsw_rbnode_t *rn = (jsw_rbnode_t *)malloc ( sizeof *rn ); + + if ( rn == NULL ) + return NULL; + + rn->red = 1; + rn->data = tree->dup ( data ); + rn->link[0] = rn->link[1] = NULL; + + return rn; +} + +/** + <summary> + Creates and initializes an empty red black tree with + user-defined comparison, data copy, and data release operations + <summary> + <param name="cmp">User-defined data comparison function</param> + <param name="dup">User-defined data copy function</param> + <param name="rel">User-defined data release function</param> + <returns>A pointer to the new tree</returns> + <remarks> + The returned pointer must be released with jsw_rbdelete + </remarks> +*/ +jsw_rbtree_t *jsw_rbnew ( cmp_f cmp, dup_f dup, rel_f rel ) +{ + jsw_rbtree_t *rt = (jsw_rbtree_t *)malloc ( sizeof *rt ); + + if ( rt == NULL ) + return NULL; + + rt->root = NULL; + rt->cmp = cmp; + rt->dup = dup; + rt->rel = rel; + rt->size = 0; + + return rt; +} + +/** + <summary> + Releases a valid red black tree + <summary> + <param name="tree">The tree to release</param> + <remarks> + The tree must have been created using jsw_rbnew + </remarks> +*/ +void jsw_rbdelete ( jsw_rbtree_t *tree ) +{ + jsw_rbnode_t *it = tree->root; + jsw_rbnode_t *save; + + /* + Rotate away the left links so that + we can treat this like the destruction + of a linked list + */ + while ( it != NULL ) { + if ( it->link[0] == NULL ) { + /* No left links, just kill the node and move on */ + save = it->link[1]; + tree->rel ( it->data ); + free ( it ); + } + else { + /* Rotate away the left link and check again */ + save = it->link[0]; + it->link[0] = save->link[1]; + save->link[1] = it; + } + + it = save; + } + + free ( tree ); +} + +/** + <summary> + Search for a copy of the specified + node data in a red black tree + <summary> + <param name="tree">The tree to search</param> + <param name="data">The data value to search for</param> + <returns> + A pointer to the data value stored in the tree, + or a null pointer if no data could be found + </returns> +*/ +void *jsw_rbfind ( jsw_rbtree_t *tree, void *data ) +{ + jsw_rbnode_t *it = tree->root; + + while ( it != NULL ) { + int cmp = tree->cmp( it->data, data ); + + if ( cmp == 0 ) + break; + + /* + If the tree supports duplicates, they should be + chained to the right subtree for this to work + */ + it = it->link[cmp < 0]; + } + + return it == NULL ? NULL : it->data; +} + +/** + <summary> + Insert a copy of the user-specified + data into a red black tree + <summary> + <param name="tree">The tree to insert into</param> + <param name="data">The data value to insert</param> + <returns> + 1 if the value was inserted successfully, + 0 if the insertion failed for any reason + </returns> +*/ +int jsw_rbinsert ( jsw_rbtree_t *tree, void *data ) +{ + if(tree != NULL) + { + if ( tree->root == NULL ) + { + /* + We have an empty tree; attach the + new node directly to the root + */ + tree->root = new_node ( tree, data ); + + if ( tree->root == NULL ) + return 0; + } + else { + + jsw_rbnode_t head = {0}; /* False tree root */ + jsw_rbnode_t *g, *t; /* Grandparent & parent */ + jsw_rbnode_t *p, *q; /* Iterator & parent */ + int dir = 0, last = 0; + + /* Set up our helpers */ + t = &head; + g = p = NULL; + q = t->link[1] = tree->root; + + /* Search down the tree for a place to insert */ + for ( ; ; ) { + if ( q == NULL ) { + /* Insert a new node at the first null link */ + p->link[dir] = q = new_node ( tree, data ); + + if ( q == NULL ) + return 0; + } + else if ( is_red ( q->link[0] ) && is_red ( q->link[1] ) ) { + /* Simple red violation: color flip */ + q->red = 1; + q->link[0]->red = 0; + q->link[1]->red = 0; + } + + if ( is_red ( q ) && is_red ( p ) ) { + /* Hard red violation: rotations necessary */ + int dir2 = t->link[1] == g; + + if ( q == p->link[last] ) + t->link[dir2] = jsw_single ( g, !last ); + else + t->link[dir2] = jsw_double ( g, !last ); + } + + /* + Stop working if we inserted a node. This + check also disallows duplicates in the tree + */ + if ( tree->cmp ( q->data, data ) == 0 ) + break; + + last = dir; + dir = tree->cmp ( q->data, data ) < 0; + + /* Move the helpers down */ + if ( g != NULL ) + t = g; + + g = p, p = q; + q = q->link[dir]; + } + + /* Update the root (it may be different) */ + tree->root = head.link[1]; + } + + /* Make the root black for simplified logic */ + tree->root->red = 0; + ++tree->size; + } + else + { + return 0; + } + + return 1; +} + +/** + <summary> + Remove a node from a red black tree + that matches the user-specified data + <summary> + <param name="tree">The tree to remove from</param> + <param name="data">The data value to search for</param> + <returns> + 1 if the value was removed successfully, + 0 if the removal failed for any reason + </returns> + <remarks> + The most common failure reason should be + that the data was not found in the tree + </remarks> +*/ +int jsw_rberase ( jsw_rbtree_t *tree, void *data ) +{ + if ( tree->root != NULL ) { + jsw_rbnode_t head = {0}; /* False tree root */ + jsw_rbnode_t *q, *p, *g; /* Helpers */ + jsw_rbnode_t *f = NULL; /* Found item */ + int dir = 1; + + /* Set up our helpers */ + q = &head; + g = p = NULL; + q->link[1] = tree->root; + + /* + Search and push a red node down + to fix red violations as we go + */ + while ( q->link[dir] != NULL ) { + int last = dir; + + /* Move the helpers down */ + g = p, p = q; + q = q->link[dir]; + dir = tree->cmp ( q->data, data ) < 0; + + /* + Save the node with matching data and keep + going; we'll do removal tasks at the end + */ + if ( tree->cmp ( q->data, data ) == 0 ) + f = q; + + /* Push the red node down with rotations and color flips */ + if ( !is_red ( q ) && !is_red ( q->link[dir] ) ) { + if ( is_red ( q->link[!dir] ) ) + p = p->link[last] = jsw_single ( q, dir ); + else if ( !is_red ( q->link[!dir] ) ) { + jsw_rbnode_t *s = p->link[!last]; + + if ( s != NULL ) { + if ( !is_red ( s->link[!last] ) && !is_red ( s->link[last] ) ) { + /* Color flip */ + p->red = 0; + s->red = 1; + q->red = 1; + } + else { + int dir2 = g->link[1] == p; + + if ( is_red ( s->link[last] ) ) + g->link[dir2] = jsw_double ( p, last ); + else if ( is_red ( s->link[!last] ) ) + g->link[dir2] = jsw_single ( p, last ); + + /* Ensure correct coloring */ + q->red = g->link[dir2]->red = 1; + g->link[dir2]->link[0]->red = 0; + g->link[dir2]->link[1]->red = 0; + } + } + } + } + } + + /* Replace and remove the saved node */ + if ( f != NULL ) { + tree->rel ( f->data ); + f->data = q->data; + p->link[p->link[1] == q] = + q->link[q->link[0] == NULL]; + free ( q ); + } + + /* Update the root (it may be different) */ + tree->root = head.link[1]; + + /* Make the root black for simplified logic */ + if ( tree->root != NULL ) + tree->root->red = 0; + + --tree->size; + } + + return 1; +} + +/** + <summary> + Gets the number of nodes in a red black tree + <summary> + <param name="tree">The tree to calculate a size for</param> + <returns>The number of nodes in the tree</returns> +*/ +size_t jsw_rbsize ( jsw_rbtree_t *tree ) +{ + return tree->size; +} + +/** + <summary> + Create a new traversal object + <summary> + <returns>A pointer to the new object</returns> + <remarks> + The traversal object is not initialized until + jsw_rbtfirst or jsw_rbtlast are called. + The pointer must be released with jsw_rbtdelete + </remarks> +*/ +jsw_rbtrav_t *jsw_rbtnew ( void ) +{ + return (jsw_rbtrav_t*)malloc ( sizeof ( jsw_rbtrav_t ) ); +} + +/** + <summary> + Release a traversal object + <summary> + <param name="trav">The object to release</param> + <remarks> + The object must have been created with jsw_rbtnew + </remarks> +*/ +void jsw_rbtdelete ( jsw_rbtrav_t *trav ) +{ + free ( trav ); +} + +/** + <summary> + Initialize a traversal object. The user-specified + direction determines whether to begin traversal at the + smallest or largest valued node + <summary> + <param name="trav">The traversal object to initialize</param> + <param name="tree">The tree that the object will be attached to</param> + <param name="dir"> + The direction to traverse (0 = ascending, 1 = descending) + </param> + <returns>A pointer to the smallest or largest data value</returns> + <remarks>For jsw_rbtree.c internal use only</remarks> +*/ +static void *start ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree, int dir ) +{ + trav->tree = tree; + trav->it = tree->root; + trav->top = 0; + + /* Save the path for later traversal */ + if ( trav->it != NULL ) { + while ( trav->it->link[dir] != NULL ) { + trav->path[trav->top++] = trav->it; + trav->it = trav->it->link[dir]; + } + } + + return trav->it == NULL ? NULL : trav->it->data; +} + +/** + <summary> + Traverse a red black tree in the user-specified direction + <summary> + <param name="trav">The initialized traversal object</param> + <param name="dir"> + The direction to traverse (0 = ascending, 1 = descending) + </param> + <returns> + A pointer to the next data value in the specified direction + </returns> + <remarks>For jsw_rbtree.c internal use only</remarks> +*/ +static void *move ( jsw_rbtrav_t *trav, int dir ) +{ + if ( trav->it->link[dir] != NULL ) { + /* Continue down this branch */ + trav->path[trav->top++] = trav->it; + trav->it = trav->it->link[dir]; + + while ( trav->it->link[!dir] != NULL ) { + trav->path[trav->top++] = trav->it; + trav->it = trav->it->link[!dir]; + } + } + else { + /* Move to the next branch */ + jsw_rbnode_t *last; + + do { + if ( trav->top == 0 ) { + trav->it = NULL; + break; + } + + last = trav->it; + trav->it = trav->path[--trav->top]; + } while ( last == trav->it->link[dir] ); + } + + return trav->it == NULL ? NULL : trav->it->data; +} + +/** + <summary> + Initialize a traversal object to the smallest valued node + <summary> + <param name="trav">The traversal object to initialize</param> + <param name="tree">The tree that the object will be attached to</param> + <returns>A pointer to the smallest data value</returns> +*/ +void *jsw_rbtfirst ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ) +{ + return start ( trav, tree, 0 ); /* Min value */ +} + +/** + <summary> + Initialize a traversal object to the largest valued node + <summary> + <param name="trav">The traversal object to initialize</param> + <param name="tree">The tree that the object will be attached to</param> + <returns>A pointer to the largest data value</returns> +*/ +void *jsw_rbtlast ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ) +{ + return start ( trav, tree, 1 ); /* Max value */ +} + +/** + <summary> + Traverse to the next value in ascending order + <summary> + <param name="trav">The initialized traversal object</param> + <returns>A pointer to the next value in ascending order</returns> +*/ +void *jsw_rbtnext ( jsw_rbtrav_t *trav ) +{ + return move ( trav, 1 ); /* Toward larger items */ +} + +/** + <summary> + Traverse to the next value in descending order + <summary> + <param name="trav">The initialized traversal object</param> + <returns>A pointer to the next value in descending order</returns> +*/ +void *jsw_rbtprev ( jsw_rbtrav_t *trav ) +{ + return move ( trav, 0 ); /* Toward smaller items */ +} + + + diff --git a/src/rbtree.h b/src/rbtree.h new file mode 100644 index 0000000..660e869 --- /dev/null +++ b/src/rbtree.h @@ -0,0 +1,99 @@ +#ifndef PERS_RBTREE_H +#define PERS_RBTREE_H + +/****************************************************************************** + * Project Persistency + * (c) copyright 2012 + * Company XS Embedded GmbH + *****************************************************************************/ +/****************************************************************************** + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + /** + * @file pers_rbtree.h + * @ingroup Persistence device access layer + * @author Ingo Huerner + * @brief Definition of rbtree functions + * @see + */ + + +// http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx +// http://eternallyconfuzzled.com/libs/jsw_rbtree.zip + +/* + Red Black balanced tree library + + > Created (Julienne Walker): August 23, 2003 + > Modified (Julienne Walker): March 14, 2008 + + This code is in the public domain. Anyone may + use it or change it in any way that they see + fit. The author assumes no responsibility for + damages incurred through use of the original + code or any variations thereof. + + It is requested, but not required, that due + credit is given to the original author and + anyone who has modified the code through + a header comment, such as this one. +*/ + +#ifdef __cplusplus +#include <cstddef> + +using std::size_t; + +extern "C" { +#else +#include <stddef.h> +#endif + +/* Opaque types */ +typedef struct jsw_rbtree jsw_rbtree_t; +typedef struct jsw_rbtrav jsw_rbtrav_t; + +/* User-defined item handling */ +typedef int (*cmp_f) ( const void *p1, const void *p2 ); +typedef void *(*dup_f) ( void *p ); +typedef void (*rel_f) ( void *p ); + + +/* Red Black tree functions */ +jsw_rbtree_t *jsw_rbnew ( cmp_f cmp, dup_f dup, rel_f rel ); +void jsw_rbdelete ( jsw_rbtree_t *tree ); +void *jsw_rbfind ( jsw_rbtree_t *tree, void *data ); +int jsw_rbinsert ( jsw_rbtree_t *tree, void *data ); +int jsw_rberase ( jsw_rbtree_t *tree, void *data ); +size_t jsw_rbsize ( jsw_rbtree_t *tree ); + +/* Traversal functions */ +jsw_rbtrav_t *jsw_rbtnew ( void ); +void jsw_rbtdelete ( jsw_rbtrav_t *trav ); +void *jsw_rbtfirst ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ); +void *jsw_rbtlast ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree ); +void *jsw_rbtnext ( jsw_rbtrav_t *trav ); +void *jsw_rbtprev ( jsw_rbtrav_t *trav ); + +#ifdef __cplusplus +} +#endif + + +#endif /* PERS_RBTREE_H */ diff --git a/test/persistence_client_library_dbus_test.c b/test/persistence_client_library_dbus_test.c index 36c6cab..a726b51 100644 --- a/test/persistence_client_library_dbus_test.c +++ b/test/persistence_client_library_dbus_test.c @@ -28,10 +28,11 @@ int myChangeCallback(pclNotification_s * notifyStruct) { printf(" ==> * - * myChangeCallback * - *\n"); - printf("Notification received ==> lbid: %d | resource_id: %s | seat: %d | user: %d \n", notifyStruct->ldbid, + printf("Notification received ==> lbid: %d | resource_id: %s | seat: %d | user: %d | status: %d \n", notifyStruct->ldbid, notifyStruct->resource_id, notifyStruct->seat_no, - notifyStruct->user_no ); + notifyStruct->user_no, + notifyStruct->pclKeyNotify_Status ); printf(" <== * - * myChangeCallback * - *\n"); return 1; @@ -49,7 +50,7 @@ int main(int argc, char *argv[]) printf("Register for change notification\n"); ret = pclKeyRegisterNotifyOnChange(0x84, "links/last_link2", 2/*user_no*/, 1/*seat_no*/, &myChangeCallback); - //ret = pclKeyRegisterNotifyOnChange(0x84, "links/last_link3", 3/*user_no*/, 2/*seat_no*/, &myChangeCallback); + ret = pclKeyRegisterNotifyOnChange(0x84, "links/last_link3", 3/*user_no*/, 2/*seat_no*/, &myChangeCallback); ret = pclKeyRegisterNotifyOnChange(0x84, "links/last_link4", 4/*user_no*/, 1/*seat_no*/, &myChangeCallback); getchar(); |