Added reason to notification messages; started with backup file list implementation
authorIngo Huerner <ingo.huerner@xse.de>
Thu, 18 Apr 2013 09:48:29 +0000 (11:48 +0200)
committerIngo Huerner <ingo.huerner@xse.de>
Thu, 18 Apr 2013 09:48:29 +0000 (11:48 +0200)
18 files changed:
include/persistence_client_library_error_def.h
include/persistence_client_library_key.h
include_protected/persistence_client_library_data_organization.h
include_protected/persistence_client_library_db_access.h
include_protected/persistence_client_library_rc_table.h
src/Makefile.am
src/persistence_client_library.c
src/persistence_client_library_backup_filelist.c [new file with mode: 0644]
src/persistence_client_library_backup_filelist.h [new file with mode: 0644]
src/persistence_client_library_data_organization.c
src/persistence_client_library_db_access.c
src/persistence_client_library_dbus_service.c
src/persistence_client_library_file.c
src/persistence_client_library_key.c
src/persistence_client_library_prct_access.c
src/rbtree.c [new file with mode: 0644]
src/rbtree.h [new file with mode: 0644]
test/persistence_client_library_dbus_test.c

index 3cb5616..458af90 100644 (file)
@@ -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)
 
 
 /**
index 56c5c3c..0afd071 100644 (file)
@@ -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);
 
index f6fd120..c3e305a 100644 (file)
@@ -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);
 
 
index a105ac2..feeb6c1 100644 (file)
@@ -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
 //---------------------------------------------------------------------------------------------
index 813638f..77453f8 100644 (file)
@@ -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;
 
index fb737e5..060113a 100644 (file)
@@ -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)
 
index a720692..2fbae64 100644 (file)
@@ -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 (file)
index 0000000..eae4425
--- /dev/null
@@ -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 (file)
index 0000000..091a0fc
--- /dev/null
@@ -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 */
index 0dd5118..be18687 100644 (file)
@@ -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];
 
index 10cd3d5..4185a7c 100644 (file)
@@ -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
index 8a1374c..05804d7 100644 (file)
@@ -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,
index 6c65d00..fad6265 100644 (file)
 
 
 // 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;
+}
+
+
+
 
index 1469d72..0256173 100644 (file)
@@ -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;
index a1ba5bf..96b6f69 100644 (file)
@@ -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 (file)
index 0000000..6a20221
--- /dev/null
@@ -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 (file)
index 0000000..660e869
--- /dev/null
@@ -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 */
index 36c6cab..a726b51 100644 (file)
 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();