summaryrefslogtreecommitdiffstats
path: root/pki/base/tps/src/main/ConfigStore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/tps/src/main/ConfigStore.cpp')
-rw-r--r--pki/base/tps/src/main/ConfigStore.cpp893
1 files changed, 893 insertions, 0 deletions
diff --git a/pki/base/tps/src/main/ConfigStore.cpp b/pki/base/tps/src/main/ConfigStore.cpp
new file mode 100644
index 000000000..e526b4039
--- /dev/null
+++ b/pki/base/tps/src/main/ConfigStore.cpp
@@ -0,0 +1,893 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation;
+// version 2.1 of the License.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301 USA
+//
+// Copyright (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+#include "prmem.h"
+#include "prsystem.h"
+#include "plstr.h"
+#include "prio.h"
+#include "prprf.h"
+#include "main/ConfigStore.h"
+#include "main/Memory.h"
+#include "main/Util.h"
+#include "engine/RA.h"
+
+#ifdef XP_WIN32
+#define TPS_PUBLIC __declspec(dllexport)
+#else /* !XP_WIN32 */
+#define TPS_PUBLIC
+#endif /* !XP_WIN32 */
+
+#ifdef XP_WIN32
+#define TOKENDB_PUBLIC __declspec(dllexport)
+#else /* !XP_WIN32 */
+#define TOKENDB_PUBLIC
+#endif /* !XP_WIN32 */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+static PR_CALLBACK void*
+_AllocTable(void* pool, PRSize size)
+{
+ return PR_MALLOC(size);
+}
+
+static PR_CALLBACK void
+_FreeTable(void* pool, void* item)
+{
+ PR_DELETE(item);
+}
+
+static PR_CALLBACK PLHashEntry*
+_AllocEntry(void* pool, const void* key)
+{
+ return PR_NEW(PLHashEntry);
+}
+
+static PR_CALLBACK void
+_FreeEntry(void* pool, PLHashEntry* he, PRUintn flag)
+{
+ if( he == NULL ) {
+ return;
+ }
+
+ if (flag == HT_FREE_VALUE) {
+ if( he->value != NULL ) {
+ PL_strfree( (char*) he->value );
+ he->value = NULL;
+ }
+ } else if (flag == HT_FREE_ENTRY) {
+ if( he->key != NULL ) {
+ PL_strfree( (char*) he->key );
+ he->key = NULL;
+ }
+ if( he->value != NULL ) {
+ PL_strfree( (char*) he->value );
+ he->value = NULL;
+ }
+ PR_DELETE(he);
+ }
+}
+
+static PLHashAllocOps _AllocOps = {
+ _AllocTable,
+ _FreeTable,
+ _AllocEntry,
+ _FreeEntry
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+///// ConfigStoreRoot
+
+ConfigStoreRoot::ConfigStoreRoot()
+{
+ m_set = PL_NewHashTable(3, PL_HashString,
+ PL_CompareStrings, PL_CompareValues,
+ &_AllocOps, NULL);
+
+ m_set_refcount = 0;
+}
+
+// If the ConfigStoreRoot goes out of scope, we can't destroy
+// the Hashtable because others maybe depending on the values
+// inside.
+ConfigStoreRoot::~ConfigStoreRoot ()
+{
+ if( m_set != NULL ) {
+ if (m_set_refcount==0) {
+ PL_HashTableDestroy( m_set );
+ m_set = NULL;
+ }
+ }
+}
+
+void ConfigStoreRoot::addref()
+{
+ m_set_refcount++;
+}
+
+void ConfigStoreRoot::release()
+{
+ m_set_refcount--;
+}
+
+PLHashTable *ConfigStoreRoot::getSet()
+{
+ return m_set;
+}
+
+
+// ConfigureStore
+
+ConfigStore::ConfigStore(ConfigStoreRoot* root, const char *subStoreName)
+{
+ m_substore_name = PL_strdup(subStoreName);
+ m_root = root;
+ root->addref();
+ m_lock = PR_NewLock();
+}
+
+ConfigStore::~ConfigStore ()
+{
+ if (m_substore_name != NULL) {
+ PR_Free(m_substore_name);
+ }
+ if (m_cfg_file_path != NULL) {
+ PR_Free(m_cfg_file_path);
+ }
+ m_root->release();
+ delete m_root;
+
+ if (m_lock != NULL )
+ PR_DestroyLock(m_lock);
+}
+
+
+
+/*
+ConfigStore::ConfigStore(const ConfigStore &X)
+{
+ m_substore_name = X.m_substore_name;
+ m_root = X.m_root;
+ m_root.addref();
+}
+
+*/
+
+
+
+ConfigStore ConfigStore::GetSubStore(const char *substore)
+{
+ char *newname=NULL;
+ const char *name = m_substore_name;
+ if (strlen(name)==0) { // this is the root
+ newname = PL_strdup(substore);
+ } else {
+ newname = PR_smprintf("%s.%s",name,substore);
+ }
+ return ConfigStore(m_root,newname);
+}
+
+/**
+ * Reads configuration file and puts name value
+ * pair into the global hashtable.
+ */
+static int ReadLine(PRFileDesc *f, char *buf, int buf_len, int *removed_return)
+{
+ char *cur = buf;
+ int sum = 0;
+ PRInt32 rc;
+
+ *removed_return = 0;
+ while (1) {
+ rc = PR_Read(f, cur, 1);
+ if (rc == -1 || rc == 0)
+ break;
+ if (*cur == '\r') {
+ continue;
+ }
+ if (*cur == '\n') {
+ *cur = '\0';
+ *removed_return = 1;
+ break;
+ }
+ sum++;
+ cur++;
+ }
+ return sum;
+}
+
+#define MAX_CFG_LINE_LEN 4096
+
+ConfigStore *ConfigStore::CreateFromConfigFile(const char *cfg_path)
+{
+ PRFileDesc *f = NULL;
+ int removed_return;
+ char line[MAX_CFG_LINE_LEN];
+ ConfigStoreRoot *root = NULL;
+ ConfigStore *cfg = NULL;
+
+ f = PR_Open(cfg_path, PR_RDWR, 00400|00200);
+ if (f == NULL)
+ goto loser;
+
+ root = new ConfigStoreRoot();
+ cfg = new ConfigStore(root,"");
+
+ while (1) {
+ int n = ReadLine(f, line, MAX_CFG_LINE_LEN, &removed_return);
+ if (n > 0) {
+ if (line[0] == '#') // handle comment line
+ continue;
+ int c = 0;
+ while ((c < n) && (line[c] != '=')) {
+ c++;
+ }
+ if (c < n) {
+ line[c] = '\0';
+ } else {
+ continue; /* no '=', skip this line */
+ }
+ cfg->Add(line, &line[c+1]);
+ } else if (n == 0 && removed_return == 1) {
+ continue; /* skip empty line */
+ } else {
+ break;
+ }
+ }
+ if( f != NULL ) {
+ PR_Close( f );
+ f = NULL;
+ }
+ cfg->SetFilePath(cfg_path);
+
+loser:
+ return cfg;
+}
+
+/**
+ * Parses string of format "n1=v1&n2=v2..."
+ * into a ConfigStore.
+ */
+ConfigStore *ConfigStore::Parse(const char *s, const char *separator)
+{
+ char *pair;
+ char *line = NULL;
+ int i;
+ int len;
+ char *lasts = NULL;
+
+ if (s == NULL)
+ return NULL;
+ ConfigStoreRoot *root = new ConfigStoreRoot();
+ ConfigStore *set= new ConfigStore(root,"");
+
+ line = PL_strdup(s);
+ pair = PL_strtok_r(line, separator, &lasts);
+ while (pair != NULL) {
+ len = strlen(pair);
+ i = 0;
+ while (1) {
+ if (i >= len) {
+ goto skip;
+ }
+ if (pair[i] == '\0') {
+ goto skip;
+ }
+ if (pair[i] == '=') {
+ pair[i] = '\0';
+ break;
+ }
+ i++;
+ }
+ set->Add(&pair[0], &pair[i+1]);
+skip:
+ pair = PL_strtok_r(NULL, separator, &lasts);
+ }
+ if( line != NULL ) {
+ PL_strfree( line );
+ line = NULL;
+ }
+ return set;
+}
+
+typedef struct {
+ int index;
+ char *key;
+} Criteria;
+
+typedef struct {
+ PRCList list;
+ char *key;
+} OrderedEntry_t;
+
+typedef struct {
+ regex_t *regex;
+ ConfigStore *store;
+} PatternEntry_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+static PRIntn CountLoop(PLHashEntry *he, PRIntn index, void *arg)
+{
+ Criteria *criteria = (Criteria *)arg;
+ criteria->index++;
+ return HT_ENUMERATE_NEXT;
+}
+
+static PRIntn Loop(PLHashEntry *he, PRIntn index, void *arg)
+{
+ Criteria *criteria = (Criteria *)arg;
+ if (criteria != NULL && index == criteria->index) {
+ criteria->key = (char *)he->key;
+ return HT_ENUMERATE_STOP;
+ } else {
+ return HT_ENUMERATE_NEXT;
+ }
+}
+
+/**
+ * Called from PL_HashTableEnumerateEntries
+ * A pointer to a PRCList (circular linked list) is passed in.
+ * Once enumeration is complete, the PRCList will contain a lexically
+ * ordered list of a copy of the keys in the hash.
+ * The caller needs to free the copies
+ */
+static PRIntn OrderLoop(PLHashEntry *he, PRIntn index, void *arg)
+{
+ PRCList *qp = (PRCList *)arg;
+ OrderedEntry_t *entry;
+
+ if (he != NULL) {
+ entry = (OrderedEntry_t *) PR_Malloc(sizeof(OrderedEntry_t));
+ entry->key = PL_strdup((char *) he->key);
+ if (index ==0) {
+ PR_APPEND_LINK((PRCList *)entry, qp);
+ return HT_ENUMERATE_NEXT;
+ }
+ PRCList *head = PR_LIST_HEAD(qp);
+ PRCList *next;
+ while (head != qp) {
+ OrderedEntry_t *current = (OrderedEntry_t *) head;
+ if (strcmp((char *) he->key, (char *) current->key) <=0)
+ break;
+ next = PR_NEXT_LINK(head);
+ head = next;
+ }
+ PR_INSERT_BEFORE((PRCList*) entry, head);
+ return HT_ENUMERATE_NEXT;
+ } else {
+ return HT_ENUMERATE_STOP;
+ }
+}
+
+/**
+ * Called from PL_HashTableEnumerateEntries
+ * A pointer to a PatternEntry is passed in. A PatternEntry consists of
+ * a pointer a regex_t and a pointer to a new config store.
+ * Once enumeration is complete, the new config store will contain
+ * all the parameters (key and values) whose keys match the regex.
+ */
+static PRIntn PatternLoop(PLHashEntry *he, PRIntn index, void *arg)
+{
+ PatternEntry_t *entry = (PatternEntry_t *) arg;
+
+ if (entry == NULL) {
+ return HT_ENUMERATE_STOP;
+ }
+
+ regex_t *r = entry->regex;
+ ConfigStore *store = entry->store;
+
+ if ((r == NULL) || (store == NULL)) {
+ return HT_ENUMERATE_STOP;
+ }
+
+ size_t no_sub = r->re_nsub+1;
+ regmatch_t *result = NULL;
+
+ result = (regmatch_t *) PR_Malloc(sizeof(regmatch_t) * no_sub);
+
+ if ((he != NULL) && (he->key != NULL) && (he->value != NULL)) {
+ if (regexec(r, (char *) he->key, no_sub, result, 0)==0) {
+ // Found a match
+ store->Add((const char*) he->key, (const char *) he->value);
+ }
+ } else {
+ return HT_ENUMERATE_STOP;
+ }
+
+ if (result != NULL) PR_Free(result);
+ return HT_ENUMERATE_NEXT;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int ConfigStore::Size()
+{
+ Criteria criteria;
+ criteria.index = 0;
+ criteria.key = NULL;
+
+ PR_Lock(m_lock);
+ PL_HashTableEnumerateEntries(m_root->getSet(), &CountLoop, &criteria);
+ PR_Unlock(m_lock);
+
+ return criteria.index;
+}
+
+const char *ConfigStore::GetNameAt(int pos)
+{
+ Criteria criteria;
+ criteria.index = pos;
+ criteria.key = NULL;
+
+ PR_Lock(m_lock);
+ PL_HashTableEnumerateEntries(m_root->getSet(), &Loop, &criteria);
+ PR_Unlock(m_lock);
+
+ return criteria.key;
+}
+
+/**
+ * Checks if a key is defined.
+ */
+int ConfigStore::IsNameDefined(const char *name)
+{
+ if (m_root->getSet()!= NULL) {
+ if (GetConfig(name) != NULL)
+ return 1;
+ }
+ return 0;
+}
+
+void ConfigStore::SetFilePath(const char* cfg_file_path)
+{
+ m_cfg_file_path = PL_strdup(cfg_file_path);
+}
+
+void ConfigStore::Add(const char *name, const char *value)
+{
+ if (IsNameDefined(name)) {
+ PR_Lock(m_lock);
+ PL_HashTableRemove(m_root->getSet(), name);
+ PL_HashTableAdd(m_root->getSet(), PL_strdup(name), PL_strdup(value));
+ PR_Unlock(m_lock);
+ } else {
+ PR_Lock(m_lock);
+ PL_HashTableAdd(m_root->getSet(), PL_strdup(name), PL_strdup(value));
+ PR_Unlock(m_lock);
+ }
+}
+
+void ConfigStore::Remove(const char *name)
+{
+ if (IsNameDefined(name)) {
+ PR_Lock(m_lock);
+ PL_HashTableRemove(m_root->getSet(), name);
+ PR_Unlock(m_lock);
+ }
+}
+
+const char *ConfigStore::GetConfig(const char *name)
+{
+ char buf[256];
+ char *ret;
+ if (m_root->getSet() ==NULL) {
+ return NULL;
+ }
+ if (PL_strlen(m_substore_name) == 0) {
+ PL_strncpy(buf,name,256);
+ } else {
+ PR_snprintf(buf,256,"%s.%s",m_substore_name,name);
+ }
+
+ PR_Lock(m_lock);
+ ret = (char *)PL_HashTableLookupConst(m_root->getSet(), buf);
+ PR_Unlock(m_lock);
+
+ return ret;
+}
+
+/**
+ * Retrieves configuration value as integer.
+ */
+int ConfigStore::GetConfigAsInt(const char *name)
+{
+ char *value = NULL;
+ value = (char *)GetConfig(name);
+ if (value == NULL)
+ return 0;
+ return atoi(value);
+}
+
+/**
+ * Retrieves configuration value as integer. If name is
+ * not defined, default value is returned.
+ */
+TPS_PUBLIC int ConfigStore::GetConfigAsInt(const char *name, int def)
+{
+ char *value = NULL;
+
+ value = (char *)GetConfig(name);
+ if (value == NULL)
+ return def;
+ return atoi(value);
+}
+
+
+/**
+ * Retrieves configuration value as unsigned integer.
+ */
+unsigned int ConfigStore::GetConfigAsUnsignedInt(const char *name)
+{
+ char *value = NULL;
+ int i = 0;
+
+ value = (char *)GetConfig(name);
+ if (value == NULL) {
+ return 0;
+ }
+
+ i = atoi(value);
+ if (i < 0) {
+ return 0;
+ }
+ return i;
+}
+
+/**
+ * Retrieves configuration value as unsigned integer. If name is
+ * not defined, default value is returned.
+ */
+TPS_PUBLIC unsigned int ConfigStore::GetConfigAsUnsignedInt(const char *name, unsigned int def)
+{
+ char *value = NULL;
+ int i = 0;
+
+ value = (char *)GetConfig(name);
+ if (value == NULL) {
+ return def;
+ }
+
+ i = atoi(value);
+ if (i < 0) {
+ return def;
+ }
+ return i;
+}
+
+
+/**
+ * Retrieves configuration value as boolean.
+ */
+bool ConfigStore::GetConfigAsBool(const char *name)
+{
+ char *value = NULL;
+
+ value = (char *)GetConfig(name);
+ if (value == NULL)
+ return false;
+ if (PL_CompareStrings("true", value) != 0)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Retrieves configuration value as boolean. If name is
+ * not defined, default value is returned.
+ */
+TPS_PUBLIC bool ConfigStore::GetConfigAsBool(const char *name, bool def)
+{
+ char *value = NULL;
+
+ value = (char *)GetConfig(name);
+ if (value == NULL)
+ return def;
+
+ if (PL_CompareStrings("true", value) != 0)
+ return true;
+ else if (PL_CompareStrings("false", value) != 0)
+ return false;
+ else
+ return def;
+}
+
+/**
+ * Retrieves configuration value as string. If key is
+ * not defined, default value is returned.
+ */
+TOKENDB_PUBLIC const char *ConfigStore::GetConfigAsString(const char *name, const char *def)
+{
+ char *value = NULL;
+
+ value = (char *)GetConfig(name);
+ if (value == NULL)
+ return def;
+ return value;
+}
+
+/**
+ * Retrieves configuration value as string.
+ */
+TPS_PUBLIC const char *ConfigStore::GetConfigAsString(const char *name)
+{
+ return (char *)GetConfig(name);
+}
+
+
+/**
+ * Allow operator[] overloading for retrieval of config strings
+ */
+const char* ConfigStore::operator[](const char*name)
+{
+ return GetConfigAsString(name);
+}
+
+
+Buffer *ConfigStore::GetConfigAsBuffer(const char *key)
+{
+ return GetConfigAsBuffer(key, NULL);
+}
+
+Buffer *ConfigStore::GetConfigAsBuffer(const char *key, const char *def)
+{
+ const char *value = NULL;
+
+ value = (char *)GetConfig(key);
+ if (value == NULL) {
+ if (def == NULL) {
+ return NULL;
+ } else {
+ return Util::Str2Buf(def);
+ }
+ } else {
+ return Util::Str2Buf(value);
+ }
+}
+
+/**
+ * returns a string containing all the parameters in the ConfigStore hash set in the
+ * format key1=value1&&key2=value2&& ...
+ * The list will be lexically ordered by parameter key values.
+ * The string needs to be freed by the caller.
+ **/
+TPS_PUBLIC const char* ConfigStore::GetOrderedList()
+{
+ char *outstr = NULL;
+ char *new_string = NULL;
+ PRCList order_list;
+ PR_INIT_CLIST(&order_list);
+
+ PR_Lock(m_lock);
+ PL_HashTableEnumerateEntries(m_root->getSet(), &OrderLoop, &order_list);
+ PR_Unlock(m_lock);
+
+ PRCList *current = PR_LIST_HEAD(&order_list);
+ PRCList *next;
+
+ outstr = (char*) PR_Malloc(128);
+ int allocated = 128;
+ int needed = 0;
+ PR_snprintf(outstr, 128, "");
+
+ while (current != &order_list) {
+ OrderedEntry_t *entry = (OrderedEntry_t *) current;
+ const char *value = GetConfigAsString(entry->key, "");
+
+ if ((entry != NULL) && (entry->key != NULL)) {
+ needed = PL_strlen(outstr) + PL_strlen(entry->key) + PL_strlen(value) + 4;
+ if (allocated <= needed) {
+ while (allocated <= needed) {
+ allocated = allocated * 2;
+ }
+ new_string = (char *)PR_Malloc(allocated);
+ PR_snprintf(new_string, allocated, "%s", outstr);
+ PR_Free(outstr);
+ outstr = new_string;
+ }
+
+ PL_strcat(outstr, entry->key);
+ PL_strcat(outstr, "=");
+ PL_strcat(outstr, value);
+
+ // free the memory for the Ordered Entry
+ PL_strfree(entry->key);
+ }
+
+ next = PR_NEXT_LINK(current);
+ PR_REMOVE_AND_INIT_LINK(current);
+ if (current != NULL) {
+ PR_Free(current);
+ }
+ current = next;
+
+ if (current != &order_list) PL_strcat(outstr, "&&");
+ }
+ return outstr;
+}
+
+/**
+ * Commits changes to the config file
+ */
+TPS_PUBLIC int ConfigStore::Commit(const bool backup, char *error_msg, int len)
+{
+ char name_tmp[256], cdate[256], name_bak[256], bak_dir[256];
+ char basename[256], dirname[256];
+ PRFileDesc *ftmp = NULL;
+ PRExplodedTime time;
+ PRTime now;
+ PRStatus status;
+
+ if (m_cfg_file_path == NULL) {
+ PR_snprintf(error_msg, len, "ConfigStore::Commit(): m_cfg_file_path is NULL!");
+ return 1;
+ }
+
+ if (strrchr(m_cfg_file_path, '/') != NULL) {
+ PR_snprintf((char *) basename, 256, "%s", strrchr(m_cfg_file_path, '/') +1);
+ PR_snprintf((char *) dirname, PL_strlen(m_cfg_file_path) - PL_strlen(basename), "%s", m_cfg_file_path);
+ PL_strcat(dirname, '\0');
+ } else {
+ PR_snprintf((char *) basename, 256, "%s", m_cfg_file_path);
+ PR_snprintf((char *) dirname, 256, ".");
+ }
+ PR_snprintf(bak_dir, 256, "%s/bak", dirname);
+
+ now = PR_Now();
+ PR_ExplodeTime(now, PR_LocalTimeParameters, &time);
+ PR_snprintf(cdate, 16, "%04d%02d%02d%02d%02d%02dZ",
+ time.tm_year, (time.tm_month + 1), time.tm_mday,
+ time.tm_hour, time.tm_min, time.tm_sec);
+ PR_snprintf(name_tmp, 256, "%s.%s.tmp", m_cfg_file_path,cdate);
+ PR_snprintf(name_bak, 256, "%s/%s.%s", bak_dir, basename, cdate);
+
+ ftmp = PR_Open(name_tmp, PR_WRONLY| PR_CREATE_FILE, 00400|00200);
+ if (ftmp == NULL) {
+ // unable to create temporary config file
+ PR_snprintf(error_msg, len, "ConfigStore::Commit(): unable to create temporary config file");
+ return 1;
+ }
+
+ PRCList order_list;
+ PR_INIT_CLIST(&order_list);
+
+ PR_Lock(m_lock);
+ PL_HashTableEnumerateEntries(m_root->getSet(), &OrderLoop, &order_list);
+ PR_Unlock(m_lock);
+
+ PRCList *current = PR_LIST_HEAD(&order_list);
+ PRCList *next;
+
+ while (current != &order_list) {
+ OrderedEntry_t *entry = (OrderedEntry_t *) current;
+ PR_Write(ftmp, entry->key, PL_strlen(entry->key));
+ PR_Write(ftmp, "=", 1);
+ const char *value = GetConfigAsString(entry->key, "");
+ PR_Write(ftmp, value, PL_strlen(value));
+ PR_Write(ftmp, "\n", 1);
+
+ // free the memory for the Ordered Entry
+ if (entry->key != NULL) PL_strfree(entry->key);
+
+ next = PR_NEXT_LINK(current);
+ PR_REMOVE_AND_INIT_LINK(current);
+ if (current != NULL) {
+ PR_Free(current);
+ }
+ current = next;
+ }
+
+ PR_Close(ftmp);
+
+ if (backup) {
+ // create the backup directory if it does not exist
+ if (PR_Access(bak_dir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
+ PR_MkDir(bak_dir, 00770);
+ }
+ status = PR_Rename(m_cfg_file_path, name_bak);
+ if (status != PR_SUCCESS) {
+ // failed to back up CS.cfg
+ }
+ }
+ if (PR_Access(m_cfg_file_path, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ // backup is false, or backup failed
+ status = PR_Delete(m_cfg_file_path);
+ if (status != PR_SUCCESS) {
+ // failed to delete old CS.cfg file
+ PR_snprintf(error_msg, len, "ConfigStore::Commit(): unable to delete old CS.cfg file");
+ return 1;
+ }
+ }
+
+ status = PR_Rename(name_tmp, m_cfg_file_path);
+ if (status != PR_SUCCESS) {
+ // failed to move tmp to CS.cfg
+ // major badness - we now have only tmp file, no CS.cfg
+ PR_snprintf(error_msg, len, "ConfigStore::Commit(): failed to move tmp file to CS.cfg");
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Takes in a string containing a regular expression.
+ * Returns a new ConfigStore which contains only those parameters whose
+ * keys match the pattern.
+ * The new Configstore must of course be freed by the caller.
+ **/
+ConfigStore *ConfigStore::GetPatternSubStore(const char *pattern)
+{
+
+ ConfigStoreRoot *root = NULL;
+ ConfigStore *ret = NULL;
+ PatternEntry_t entry;
+ regex_t *regex = NULL;
+ int err_no=0; /* For regerror() */
+
+ regex = (regex_t *) malloc(sizeof(regex_t));
+ memset(regex, 0, sizeof(regex_t));
+
+ if((err_no=regcomp(regex, pattern, 0))!=0) /* Compile the regex */
+ {
+ // Error in computing the regex
+ size_t length;
+ char *buffer;
+ length = regerror (err_no, regex, NULL, 0);
+ buffer = (char *) PR_Malloc(length);
+ regerror (err_no, regex, buffer, length);
+ // PR_fprintf(m_dump_f, "%s\n", buffer); /* Print the error */
+ PR_Free(buffer);
+ regfree(regex);
+ return NULL;
+ }
+
+ entry.regex = regex;
+ root = new ConfigStoreRoot();
+ ret = new ConfigStore(root, "");
+ entry.store = ret;
+
+ PR_Lock(m_lock);
+ PL_HashTableEnumerateEntries(m_root->getSet(), &PatternLoop, &entry);
+ PR_Unlock(m_lock);
+
+ /* cleanup */
+ //regfree(entry.regex);
+ //entry.store = NULL;
+
+ ret->SetFilePath("");
+ return ret;
+}
+