* prof_tree.c (struct profile_node): Add new bitfield DELETED.
[krb5.git] / src / util / profile / prof_set.c
1 /*
2  * prof_set.c --- routines that expose the public interfaces for
3  *      inserting, updating and deleting items from the profile.
4  *
5  * WARNING: These routines only look at the first file opened in the
6  * profile.  It's not clear how to handle multiple files, actually.
7  * In the future it may be necessary to modify this public interface,
8  * or possibly add higher level functions to support this correctly.
9  *
10  * WARNING: We're not yet doing locking yet, either.  
11  *
12  */
13
14 #include "prof_int.h"
15
16 #include <stdio.h>
17 #include <string.h>
18 #ifdef HAVE_STDLIB_H
19 #include <stdlib.h>
20 #endif
21 #include <errno.h>
22
23 static errcode_t rw_setup(profile_t profile)
24 {
25         prf_file_t      file;
26         errcode_t       retval = 0;
27
28         if (!profile)
29                 return PROF_NO_PROFILE;
30
31         if (profile->magic != PROF_MAGIC_PROFILE)
32                 return PROF_MAGIC_PROFILE;
33
34         file = profile->first_file;
35
36         if (!(file->data->flags & PROFILE_FILE_RW))
37             return PROF_READ_ONLY;
38
39         retval = profile_lock_global();
40         if (retval)
41             return retval;
42
43         /* Don't update the file if we've already made modifications */
44         if (file->data->flags & PROFILE_FILE_DIRTY) {
45             profile_unlock_global();
46             return 0;
47         }
48
49 #ifdef SHARE_TREE_DATA
50         if ((file->data->flags & PROFILE_FILE_SHARED) != 0) {
51             prf_data_t new_data;
52             new_data = malloc(sizeof(struct _prf_data_t));
53             if (new_data == NULL) {
54                 retval = ENOMEM;
55             } else {
56                 *new_data = *file->data;
57                 /* We can blow away the information because update
58                    will be called further down */
59                 new_data->comment = NULL;
60                 new_data->root = NULL;
61                 new_data->flags &= ~PROFILE_FILE_SHARED;
62                 new_data->timestamp = 0;
63                 /* copy the file spec */
64                 new_data->filespec = malloc(strlen(file->data->filespec) + 1);
65                 if (new_data->filespec == NULL) {
66                     retval = ENOMEM;
67                 } else {
68                     strcpy (new_data->filespec, file->data->filespec);
69                 }
70             }
71
72             if (retval != 0) {
73                 profile_unlock_global();
74                 free(new_data);
75                 return retval;
76             }
77             profile_dereference_data(file->data);
78             file->data = new_data;
79         }
80 #endif /* SHARE_TREE_DATA */
81
82         profile_unlock_global();
83         retval = profile_update_file(file);
84
85         return retval;
86 }
87
88
89 /* 
90  * Delete or update a particular child node 
91  * 
92  * ADL - 2/23/99, rewritten TYT 2/25/99
93  */
94 errcode_t KRB5_CALLCONV
95 profile_update_relation(profile_t profile, const char **names,
96                         const char *old_value, const char *new_value)
97 {       
98         errcode_t       retval;
99         struct profile_node *section, *node;
100         void            *state;
101         const char      **cpp;
102
103         retval = rw_setup(profile);
104         if (retval)
105                 return retval;
106         
107         if (names == 0 || names[0] == 0 || names[1] == 0)
108                 return PROF_BAD_NAMESET;
109
110         if (!old_value || !*old_value)
111                 return PROF_EINVAL;
112
113         retval = k5_mutex_lock(&profile->first_file->data->lock);
114         if (retval)
115             return retval;
116         section = profile->first_file->data->root;
117         for (cpp = names; cpp[1]; cpp++) {
118                 state = 0;
119                 retval = profile_find_node(section, *cpp, 0, 1,
120                                            &state, &section);
121                 if (retval) {
122                     k5_mutex_unlock(&profile->first_file->data->lock);
123                     return retval;
124                 }
125         }
126
127         state = 0;
128         retval = profile_find_node(section, *cpp, old_value, 0, &state, &node);
129         if (retval == 0) {
130             if (new_value)
131                 retval = profile_set_relation_value(node, new_value);
132             else
133                 retval = profile_remove_node(node);
134         }
135         if (retval == 0)
136             profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
137         k5_mutex_unlock(&profile->first_file->data->lock);
138         
139         return retval;
140 }
141
142 /* 
143  * Clear a particular all of the relations with a specific name.
144  * 
145  * TYT - 2/25/99
146  */
147 errcode_t KRB5_CALLCONV
148 profile_clear_relation(profile_t profile, const char **names)
149 {       
150         errcode_t       retval;
151         struct profile_node *section, *node;
152         void            *state;
153         const char      **cpp;
154
155         retval = rw_setup(profile);
156         if (retval)
157                 return retval;
158         
159         if (names == 0 || names[0] == 0 || names[1] == 0)
160                 return PROF_BAD_NAMESET;
161
162         section = profile->first_file->data->root;
163         for (cpp = names; cpp[1]; cpp++) {
164                 state = 0;
165                 retval = profile_find_node(section, *cpp, 0, 1,
166                                            &state, &section);
167                 if (retval)
168                         return retval;
169         }
170
171         state = 0;
172         do {
173                 retval = profile_find_node(section, *cpp, 0, 0, &state, &node);
174                 if (retval)
175                         return retval;
176                 retval = profile_remove_node(node);
177                 if (retval)
178                         return retval;
179         } while (state);
180
181         profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
182         
183         return 0;
184 }
185
186 /* 
187  * Rename a particular section; if the new_section name is NULL,
188  * delete it.
189  * 
190  * ADL - 2/23/99, rewritten TYT 2/25/99
191  */
192 errcode_t KRB5_CALLCONV
193 profile_rename_section(profile_t profile, const char **names,
194                        const char *new_name)
195 {       
196         errcode_t       retval;
197         struct profile_node *section, *node;
198         void            *state;
199         const char      **cpp;
200         
201         retval = rw_setup(profile);
202         if (retval)
203                 return retval;
204         
205         if (names == 0 || names[0] == 0 || names[1] == 0)
206                 return PROF_BAD_NAMESET;
207
208         retval = k5_mutex_lock(&profile->first_file->data->lock);
209         if (retval)
210             return retval;
211         section = profile->first_file->data->root;
212         for (cpp = names; cpp[1]; cpp++) {
213                 state = 0;
214                 retval = profile_find_node(section, *cpp, 0, 1,
215                                            &state, &section);
216                 if (retval) {
217                     k5_mutex_unlock(&profile->first_file->data->lock);
218                     return retval;
219                 }
220         }
221
222         state = 0;
223         retval = profile_find_node(section, *cpp, 0, 1, &state, &node);
224         if (retval == 0) {
225             if (new_name)
226                 retval = profile_rename_node(node, new_name);
227             else
228                 retval = profile_remove_node(node);
229         }
230         if (retval == 0)
231             profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
232         k5_mutex_unlock(&profile->first_file->data->lock);
233         return retval;
234 }
235
236 /*
237  * Insert a new relation.  If the new_value argument is NULL, then
238  * create a new section instead.
239  *
240  * Note: if the intermediate sections do not exist, this function will
241  * automatically create them.
242  *
243  * ADL - 2/23/99, rewritten TYT 2/25/99
244  */
245 errcode_t KRB5_CALLCONV
246 profile_add_relation(profile_t profile, const char **names,
247                      const char *new_value)
248 {
249         errcode_t       retval;
250         struct profile_node *section;
251         const char      **cpp;
252         void            *state;
253
254         retval = rw_setup(profile);
255         if (retval)
256                 return retval;
257         
258         if (names == 0 || names[0] == 0 || names[1] == 0)
259                 return PROF_BAD_NAMESET;
260
261         retval = k5_mutex_lock(&profile->first_file->data->lock);
262         if (retval)
263             return retval;
264         section = profile->first_file->data->root;
265         for (cpp = names; cpp[1]; cpp++) {
266                 state = 0;
267                 retval = profile_find_node(section, *cpp, 0, 1,
268                                            &state, &section);
269                 if (retval == PROF_NO_SECTION)
270                         retval = profile_add_node(section, *cpp, 0, &section);
271                 if (retval) {
272                     k5_mutex_unlock(&profile->first_file->data->lock);
273                     return retval;
274                 }
275         }
276
277         if (new_value == 0) {
278                 retval = profile_find_node(section, *cpp, 0, 1, &state, 0);
279                 if (retval == 0) {
280                     k5_mutex_unlock(&profile->first_file->data->lock);
281                     return PROF_EXISTS;
282                 } else if (retval != PROF_NO_SECTION) {
283                     k5_mutex_unlock(&profile->first_file->data->lock);
284                     return retval;
285                 }
286         }
287
288         retval = profile_add_node(section, *cpp, new_value, 0);
289         if (retval) {
290             k5_mutex_unlock(&profile->first_file->data->lock);
291             return retval;
292         }
293
294         profile->first_file->data->flags |= PROFILE_FILE_DIRTY;
295         k5_mutex_unlock(&profile->first_file->data->lock);
296         return 0;
297 }
298