]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Make profile_copy() work on dirty profiles 1339/head
authorGreg Hudson <ghudson@mit.edu>
Wed, 3 Apr 2024 18:13:50 +0000 (14:13 -0400)
committerGreg Hudson <ghudson@mit.edu>
Mon, 22 Apr 2024 22:58:20 +0000 (18:58 -0400)
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
src/util/profile/prof_init.c
src/util/profile/prof_int.h
src/util/profile/prof_tree.c
src/util/profile/profile.hin
src/util/profile/t_profile.c

index a39a5dc181065c89e88c99deb74b501cf743e9ea..5567903ce14a315fb9bf5bcdd14803f32367a1cc 100644 (file)
@@ -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);
index c6c48b5949ab1ee24ab6cf00798958a1982dbae1..1cf7a94518a3861e14ac72f98d895fee0bcd7240 100644 (file)
@@ -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
index 95f7b346f89f38aa48bff796e0b4a3fa594b7c90..6bd30a37344dfe005cabf6f25b52a2a292ec3a41 100644 (file)
@@ -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);
 
index b6bdbf3f60d8bfcf6f5dc5153078c0ff471b7f48..3e2aaa1cf611560877a6fa359e7e27259aa17c52 100644 (file)
@@ -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,
index 45ad55430b827d5f6cc0dd0270eb11c877abd25c..fef2b62f25f83f8b4f2695d5f7179c0d1599e98b 100644 (file)
@@ -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
index 0e859b97c648ab0553434af95395cf380e82ca33..fd3b65ed8e3788e1ddef2223de5363bc4a5ee66d 100644 (file)
@@ -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);