aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2024-04-03 14:13:50 -0400
committerGreg Hudson <ghudson@mit.edu>2024-04-22 18:58:20 -0400
commit078721b1f4a8fb995e0d5346ecf36adffd0a4f99 (patch)
treec7e6e957c2ea35a409c98894017aeb4945282409
parent9b2fb80ad24006784170875709a04dc79e03b401 (diff)
downloadkrb5-078721b1f4a8fb995e0d5346ecf36adffd0a4f99.zip
krb5-078721b1f4a8fb995e0d5346ecf36adffd0a4f99.tar.gz
krb5-078721b1f4a8fb995e0d5346ecf36adffd0a4f99.tar.bz2
Make profile_copy() work on dirty profiles
Replace the current implementation of profile_copy() with one that copies the in-memory tree structure of non-shared data objects. Make profile_copy() a public function. ticket: 9119 (new)
-rw-r--r--src/util/profile/prof_file.c38
-rw-r--r--src/util/profile/prof_init.c36
-rw-r--r--src/util/profile/prof_int.h8
-rw-r--r--src/util/profile/prof_tree.c45
-rw-r--r--src/util/profile/profile.hin3
-rw-r--r--src/util/profile/t_profile.c9
6 files changed, 121 insertions, 18 deletions
diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c
index a39a5dc..5567903 100644
--- a/src/util/profile/prof_file.c
+++ b/src/util/profile/prof_file.c
@@ -554,6 +554,44 @@ void profile_unlock_global()
k5_mutex_unlock(&g_shared_trees_mutex);
}
+prf_file_t profile_copy_file(prf_file_t oldfile)
+{
+ prf_file_t file;
+
+ file = calloc(1, sizeof(*file));
+ if (file == NULL)
+ return NULL;
+ file->magic = PROF_MAGIC_FILE;
+
+ /* Shared data objects can just have their reference counts incremented. */
+ if (oldfile->data->flags & PROFILE_FILE_SHARED) {
+ profile_lock_global();
+ oldfile->data->refcount++;
+ profile_unlock_global();
+ file->data = oldfile->data;
+ return file;
+ }
+
+ /* Otherwise we need to copy the data object. */
+ file->data = profile_make_prf_data(oldfile->data->filespec);
+ if (file->data == NULL) {
+ free(file);
+ return NULL;
+ }
+ k5_mutex_lock(&oldfile->data->lock);
+ file->data->flags = oldfile->data->flags;
+ file->data->last_stat = oldfile->data->last_stat;
+ file->data->frac_ts = oldfile->data->frac_ts;
+ file->data->root = profile_copy_node(oldfile->data->root);
+ k5_mutex_unlock(&oldfile->data->lock);
+ if (file->data->root == NULL) {
+ profile_free_file(file);
+ return NULL;
+ }
+
+ return file;
+}
+
void profile_free_file(prf_file_t prf)
{
profile_dereference_data(prf->data);
diff --git a/src/util/profile/prof_init.c b/src/util/profile/prof_init.c
index c6c48b5..1cf7a94 100644
--- a/src/util/profile/prof_init.c
+++ b/src/util/profile/prof_init.c
@@ -293,26 +293,32 @@ copy_vtable_profile(profile_t profile, profile_t *ret_new_profile)
errcode_t KRB5_CALLCONV
profile_copy(profile_t old_profile, profile_t *new_profile)
{
- size_t size, i;
- const_profile_filespec_t *files;
- prf_file_t file;
- errcode_t err;
+ profile_t profile;
+ prf_file_t p, q, *nextp;
+
+ *new_profile = NULL;
if (old_profile->vt)
return copy_vtable_profile(old_profile, new_profile);
- /* The fields we care about are read-only after creation, so
- no locking is needed. */
- COUNT_LINKED_LIST (size, prf_file_t, old_profile->first_file, next);
- files = malloc ((size+1) * sizeof(*files));
- if (files == NULL)
+ profile = calloc(1, sizeof(*profile));
+ if (profile == NULL)
return ENOMEM;
- for (i = 0, file = old_profile->first_file; i < size; i++, file = file->next)
- files[i] = file->data->filespec;
- files[size] = NULL;
- err = profile_init (files, new_profile);
- free (files);
- return err;
+ profile->magic = PROF_MAGIC_PROFILE;
+
+ nextp = &profile->first_file;
+ for (p = old_profile->first_file; p != NULL; p = p->next) {
+ q = profile_copy_file(p);
+ if (q == NULL) {
+ profile_abandon(profile);
+ return ENOMEM;
+ }
+ *nextp = q;
+ nextp = &q->next;
+ }
+
+ *new_profile = profile;
+ return 0;
}
errcode_t KRB5_CALLCONV
diff --git a/src/util/profile/prof_int.h b/src/util/profile/prof_int.h
index 95f7b34..6bd30a3 100644
--- a/src/util/profile/prof_int.h
+++ b/src/util/profile/prof_int.h
@@ -139,6 +139,9 @@ errcode_t profile_create_node
(const char *name, const char *value,
struct profile_node **ret_node);
+struct profile_node *profile_copy_node
+ (struct profile_node *oldnode);
+
errcode_t profile_verify_node
(struct profile_node *node);
@@ -208,8 +211,6 @@ errcode_t profile_rename_node
/* prof_file.c */
-errcode_t KRB5_CALLCONV profile_copy (profile_t, profile_t *);
-
errcode_t profile_open_file
(const_profile_filespec_t file, prf_file_t *ret_prof,
char **ret_modspec);
@@ -234,6 +235,9 @@ errcode_t profile_flush_file_data_to_file
errcode_t profile_flush_file_data_to_buffer
(prf_data_t data, char **bufp);
+prf_file_t profile_copy_file
+ (prf_file_t oldfile);
+
void profile_free_file
(prf_file_t profile);
diff --git a/src/util/profile/prof_tree.c b/src/util/profile/prof_tree.c
index b6bdbf3..3e2aaa1 100644
--- a/src/util/profile/prof_tree.c
+++ b/src/util/profile/prof_tree.c
@@ -112,6 +112,51 @@ errcode_t profile_create_node(const char *name, const char *value,
return 0;
}
+/* Return a copy of oldnode. Recursively copy oldnode's children, but leave
+ * the parent, next, and prev pointers as null. */
+struct profile_node *profile_copy_node(struct profile_node *oldnode)
+{
+ struct profile_node *node = NULL, *p, *q, **nextp, *last;
+
+ if (oldnode->magic != PROF_MAGIC_NODE)
+ return NULL;
+
+ node = calloc(1, sizeof(*node));
+ node->magic = PROF_MAGIC_NODE;
+ node->name = strdup(oldnode->name);
+ if (node->name == NULL)
+ goto errout;
+ if (oldnode->value != NULL) {
+ node->value = strdup(oldnode->value);
+ if (oldnode->value == NULL)
+ goto errout;
+ }
+ node->group_level = oldnode->group_level;
+ node->final = oldnode->final;
+ node->deleted = oldnode->deleted;
+
+ nextp = &node->first_child;
+ last = NULL;
+ for (p = oldnode->first_child; p != NULL; p = p->next) {
+ q = profile_copy_node(p);
+ if (q == NULL)
+ goto errout;
+
+ /* Link in the new child and prepare for the next. */
+ q->parent = node;
+ q->prev = last;
+ last = q;
+ *nextp = q;
+ nextp = &q->next;
+ }
+
+ return node;
+
+errout:
+ profile_free_node(node);
+ return NULL;
+}
+
/*
* This function verifies that all of the representation invariants of
* the profile are true. If not, we have a programming bug somewhere,
diff --git a/src/util/profile/profile.hin b/src/util/profile/profile.hin
index 45ad554..fef2b62 100644
--- a/src/util/profile/profile.hin
+++ b/src/util/profile/profile.hin
@@ -51,6 +51,9 @@ long KRB5_CALLCONV profile_init_flags
long KRB5_CALLCONV profile_init_path
(const_profile_filespec_list_t filelist, profile_t *ret_profile);
+long KRB5_CALLCONV profile_copy
+ (profile_t, profile_t *);
+
long KRB5_CALLCONV profile_flush
(profile_t profile);
long KRB5_CALLCONV profile_flush_to_file
diff --git a/src/util/profile/t_profile.c b/src/util/profile/t_profile.c
index 0e859b9..fd3b65e 100644
--- a/src/util/profile/t_profile.c
+++ b/src/util/profile/t_profile.c
@@ -378,7 +378,7 @@ test_merge_subsections(void)
static void
test_empty(void)
{
- profile_t p;
+ profile_t p, p2;
const char *n1[] = { "section", NULL };
const char *n2[] = { "section", "var", NULL };
char **values;
@@ -390,6 +390,13 @@ test_empty(void)
check(profile_get_values(p, n2, &values));
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
profile_free_list(values);
+
+ check(profile_copy(p, &p2));
+ check(profile_get_values(p2, n2, &values));
+ assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
+ profile_free_list(values);
+ profile_release(p2);
+
profile_flush_to_file(p, "test3.ini");
profile_release(p);