[31312] in CVS-changelog-for-Kerberos-V5

home help back first fref pref prev next nref lref last post

krb5 commit: Make profile_copy() work on dirty profiles

daemon@ATHENA.MIT.EDU (ghudson@mit.edu)
Mon Apr 22 20:39:38 2024

From: ghudson@mit.edu
To: cvs-krb5@mit.edu
Message-Id: <20240423003931.D04331019B8@krbdev.mit.edu>
Date: Mon, 22 Apr 2024 20:39:31 -0400 (EDT)
MIME-Version: 1.0
Reply-To: krbdev@mit.edu
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: cvs-krb5-bounces@mit.edu

https://github.com/krb5/krb5/commit/078721b1f4a8fb995e0d5346ecf36adffd0a4f99
commit 078721b1f4a8fb995e0d5346ecf36adffd0a4f99
Author: Greg Hudson <ghudson@mit.edu>
Date:   Wed Apr 3 14:13:50 2024 -0400

    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)

 src/util/profile/prof_file.c | 38 +++++++++++++++++++++++++++++++++++++
 src/util/profile/prof_init.c | 36 ++++++++++++++++++++---------------
 src/util/profile/prof_int.h  |  8 ++++++--
 src/util/profile/prof_tree.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 src/util/profile/profile.hin |  3 +++
 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 a39a5dc18..5567903ce 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 c6c48b594..1cf7a9451 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 95f7b346f..6bd30a373 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 b6bdbf3f6..3e2aaa1cf 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 45ad55430..fef2b62f2 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 0e859b97c..fd3b65ed8 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);
 
_______________________________________________
cvs-krb5 mailing list
cvs-krb5@mit.edu
https://mailman.mit.edu/mailman/listinfo/cvs-krb5

home help back first fref pref prev next nref lref last post