summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngo Huerner <ingo.huerner@xse.de>2013-04-18 11:48:29 +0200
committerIngo Huerner <ingo.huerner@xse.de>2013-04-18 11:48:29 +0200
commit20075d4a4ab86720f0c11dca55726847db61898f (patch)
treec68fbf9c96de5259193cd86e672908100751804b
parent515004b1f75c8e2be7101732110c5b50ce9920f6 (diff)
downloadpersistence-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.h4
-rw-r--r--include/persistence_client_library_key.h28
-rw-r--r--include_protected/persistence_client_library_data_organization.h31
-rw-r--r--include_protected/persistence_client_library_db_access.h13
-rw-r--r--include_protected/persistence_client_library_rc_table.h2
-rw-r--r--src/Makefile.am7
-rw-r--r--src/persistence_client_library.c39
-rw-r--r--src/persistence_client_library_backup_filelist.c312
-rw-r--r--src/persistence_client_library_backup_filelist.h38
-rw-r--r--src/persistence_client_library_data_organization.c15
-rw-r--r--src/persistence_client_library_db_access.c188
-rw-r--r--src/persistence_client_library_dbus_service.c26
-rw-r--r--src/persistence_client_library_file.c258
-rw-r--r--src/persistence_client_library_key.c13
-rw-r--r--src/persistence_client_library_prct_access.c6
-rw-r--r--src/rbtree.c635
-rw-r--r--src/rbtree.h99
-rw-r--r--test/persistence_client_library_dbus_test.c7
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, &notifyStruct.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();