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);
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
(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);
/* 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);
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);
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,
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
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;
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);