diff options
author | Greg Hudson <ghudson@mit.edu> | 2024-04-03 14:13:50 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2024-04-22 18:58:20 -0400 |
commit | 078721b1f4a8fb995e0d5346ecf36adffd0a4f99 (patch) | |
tree | c7e6e957c2ea35a409c98894017aeb4945282409 | |
parent | 9b2fb80ad24006784170875709a04dc79e03b401 (diff) | |
download | krb5-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.c | 38 | ||||
-rw-r--r-- | src/util/profile/prof_init.c | 36 | ||||
-rw-r--r-- | src/util/profile/prof_int.h | 8 | ||||
-rw-r--r-- | src/util/profile/prof_tree.c | 45 | ||||
-rw-r--r-- | src/util/profile/profile.hin | 3 | ||||
-rw-r--r-- | src/util/profile/t_profile.c | 9 |
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); |