Imported Upstream version 1.5.0
[platform/upstream/augeas.git] / src / augeas.c
1 /*
2  * augeas.c: the core data structure for storing key/value pairs
3  *
4  * Copyright (C) 2007-2015 David Lutterkort
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  *
20  * Author: David Lutterkort <dlutter@redhat.com>
21  */
22
23 #include <config.h>
24 #include "augeas.h"
25 #include "internal.h"
26 #include "memory.h"
27 #include "syntax.h"
28 #include "transform.h"
29 #include "errcode.h"
30
31 #include <fnmatch.h>
32 #include <argz.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <locale.h>
36 #include <libxml/tree.h>
37
38 /* Some popular labels that we use in /augeas */
39 static const char *const s_augeas = "augeas";
40 static const char *const s_files  = "files";
41 static const char *const s_load   = "load";
42 static const char *const s_pathx  = "pathx";
43 static const char *const s_error  = "error";
44 static const char *const s_pos    = "pos";
45 static const char *const s_vars   = "variables";
46 static const char *const s_lens   = "lens";
47 static const char *const s_excl   = "excl";
48 static const char *const s_incl   = "incl";
49
50 #define TREE_HIDDEN(tree) ((tree)->label == NULL)
51
52 #define AUGEAS_META_PATHX_FUNC AUGEAS_META_TREE "/version/pathx/functions"
53
54 static const char *const static_nodes[][2] = {
55     { AUGEAS_FILES_TREE, NULL },
56     { AUGEAS_META_TREE "/variables", NULL },
57     { AUGEAS_META_TREE "/version", PACKAGE_VERSION },
58     { AUGEAS_META_TREE "/version/save/mode[1]", AUG_SAVE_BACKUP_TEXT },
59     { AUGEAS_META_TREE "/version/save/mode[2]", AUG_SAVE_NEWFILE_TEXT },
60     { AUGEAS_META_TREE "/version/save/mode[3]", AUG_SAVE_NOOP_TEXT },
61     { AUGEAS_META_TREE "/version/save/mode[4]", AUG_SAVE_OVERWRITE_TEXT },
62     { AUGEAS_META_TREE "/version/defvar/expr", NULL },
63     { AUGEAS_META_PATHX_FUNC "/count", NULL },
64     { AUGEAS_META_PATHX_FUNC "/glob", NULL },
65     { AUGEAS_META_PATHX_FUNC "/label", NULL },
66     { AUGEAS_META_PATHX_FUNC "/last", NULL },
67     { AUGEAS_META_PATHX_FUNC "/position", NULL },
68     { AUGEAS_META_PATHX_FUNC "/regexp", NULL }
69 };
70
71 static const char *const errcodes[] = {
72     "No error",                                         /* AUG_NOERROR */
73     "Cannot allocate memory",                           /* AUG_ENOMEM */
74     "Internal error (please file a bug)",               /* AUG_EINTERNAL */
75     "Invalid path expression",                          /* AUG_EPATHX */
76     "No match for path expression",                     /* AUG_ENOMATCH */
77     "Too many matches for path expression",             /* AUG_EMMATCH */
78     "Syntax error in lens definition",                  /* AUG_ESYNTAX */
79     "Lens not found",                                   /* AUG_ENOLENS */
80     "Multiple transforms",                              /* AUG_EMXFM */
81     "Node has no span info",                            /* AUG_ENOSPAN */
82     "Cannot move node into its descendant",             /* AUG_EMVDESC */
83     "Failed to execute command",                        /* AUG_ECMDRUN */
84     "Invalid argument in function call",                /* AUG_EBADARG */
85     "Invalid label",                                    /* AUG_ELABEL */
86     "Cannot copy node into its descendant"              /* AUG_ECPDESC */
87 };
88
89 static void tree_mark_dirty(struct tree *tree) {
90     do {
91         tree->dirty = 1;
92         tree = tree->parent;
93     } while (tree != tree->parent && !tree->dirty);
94     tree->dirty = 1;
95 }
96
97 void tree_clean(struct tree *tree) {
98     if (tree->dirty) {
99         list_for_each(c, tree->children)
100             tree_clean(c);
101     }
102     tree->dirty = 0;
103 }
104
105 struct tree *tree_child(struct tree *tree, const char *label) {
106     if (tree == NULL)
107         return NULL;
108
109     list_for_each(child, tree->children) {
110         if (streqv(label, child->label))
111             return child;
112     }
113     return NULL;
114 }
115
116 struct tree *tree_child_cr(struct tree *tree, const char *label) {
117     static struct tree *child = NULL;
118
119     if (tree == NULL)
120         return NULL;
121
122     child = tree_child(tree, label);
123     if (child == NULL) {
124         char *l = strdup(label);
125         if (l == NULL)
126             return NULL;
127         child = tree_append(tree, l, NULL);
128     }
129     return child;
130 }
131
132 struct tree *tree_path_cr(struct tree *tree, int n, ...) {
133     va_list ap;
134
135     va_start(ap, n);
136     for (int i=0; i < n; i++) {
137         const char *l = va_arg(ap, const char *);
138         tree = tree_child_cr(tree, l);
139     }
140     va_end(ap);
141     return tree;
142 }
143
144 static struct tree *tree_fpath_int(struct augeas *aug, const char *fpath,
145                                    bool create) {
146     int r;
147     char *steps = NULL, *step = NULL;
148     size_t nsteps = 0;
149     struct tree *result = NULL;
150
151     r = argz_create_sep(fpath, '/', &steps, &nsteps);
152     ERR_NOMEM(r < 0, aug);
153     result = aug->origin;
154     while ((step = argz_next(steps, nsteps, step))) {
155         if (create) {
156             result = tree_child_cr(result, step);
157             ERR_THROW(result == NULL, aug, AUG_ENOMEM,
158                       "while searching %s: can not create %s", fpath, step);
159         } else {
160             /* Lookup only */
161             result = tree_child(result, step);
162             if (result == NULL)
163                 goto done;
164         }
165     }
166  done:
167     free(steps);
168     return result;
169  error:
170     result = NULL;
171     goto done;
172 }
173
174 struct tree *tree_fpath(struct augeas *aug, const char *fpath) {
175     return tree_fpath_int(aug, fpath, false);
176 }
177
178 struct tree *tree_fpath_cr(struct augeas *aug, const char *fpath) {
179     return tree_fpath_int(aug, fpath, true);
180 }
181
182 struct tree *tree_find(struct augeas *aug, const char *path) {
183     struct pathx *p = NULL;
184     struct tree *result = NULL;
185     int r;
186
187     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
188     ERR_BAIL(aug);
189
190     r = pathx_find_one(p, &result);
191     BUG_ON(r > 1, aug,
192            "Multiple matches for %s when only one was expected",
193            path);
194  done:
195     free_pathx(p);
196     return result;
197  error:
198     result = NULL;
199     goto done;
200 }
201
202 struct tree *tree_find_cr(struct augeas *aug, const char *path) {
203     struct pathx *p = NULL;
204     struct tree *result = NULL;
205     int r;
206
207     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
208     ERR_BAIL(aug);
209
210     r = pathx_expand_tree(p, &result);
211     ERR_BAIL(aug);
212     ERR_THROW(r < 0, aug, AUG_EINTERNAL, "pathx_expand_tree failed");
213  error:
214     free_pathx(p);
215     return result;
216 }
217
218 void tree_store_value(struct tree *tree, char **value) {
219     if (streqv(tree->value, *value)) {
220         free(*value);
221         *value = NULL;
222         return;
223     }
224     if (tree->value != NULL) {
225         free(tree->value);
226         tree->value = NULL;
227     }
228     if (*value != NULL) {
229         tree->value = *value;
230         *value = NULL;
231     }
232     tree_mark_dirty(tree);
233 }
234
235 int tree_set_value(struct tree *tree, const char *value) {
236     char *v = NULL;
237
238     if (streqv(tree->value, value))
239         return 0;
240     if (value != NULL) {
241         v = strdup(value);
242         if (v == NULL)
243             return -1;
244     }
245     tree_store_value(tree, &v);
246     return 0;
247 }
248
249 static void store_error(const struct augeas *aug, const char *label, const char *value,
250                  int nentries, ...) {
251     va_list ap;
252     struct tree *tree;
253
254     ensure(nentries % 2 == 0, aug);
255     tree = tree_path_cr(aug->origin, 3, s_augeas, s_error, label);
256     if (tree == NULL)
257         return;
258
259     tree_set_value(tree, value);
260
261     va_start(ap, nentries);
262     for (int i=0; i < nentries; i += 2) {
263         char *l = va_arg(ap, char *);
264         char *v = va_arg(ap, char *);
265         struct tree *t = tree_child_cr(tree, l);
266         if (t != NULL)
267             tree_set_value(t, v);
268     }
269     va_end(ap);
270  error:
271     return;
272 }
273
274 /* Report pathx errors in /augeas/pathx/error */
275 static void store_pathx_error(const struct augeas *aug) {
276     if (aug->error->code != AUG_EPATHX)
277         return;
278
279     store_error(aug, s_pathx, aug->error->minor_details,
280                 2, s_pos, aug->error->details);
281 }
282
283 struct pathx *pathx_aug_parse(const struct augeas *aug,
284                               struct tree *tree,
285                               struct tree *root_ctx,
286                               const char *path, bool need_nodeset) {
287     struct pathx *result;
288     struct error *err = err_of_aug(aug);
289
290     if (tree == NULL)
291         tree = aug->origin;
292
293     pathx_parse(tree, err, path, need_nodeset, aug->symtab, root_ctx, &result);
294     return result;
295 }
296
297 /* Find the tree stored in AUGEAS_CONTEXT */
298 struct tree *tree_root_ctx(const struct augeas *aug) {
299     struct pathx *p = NULL;
300     struct tree *match = NULL;
301     const char *ctx_path;
302     int r;
303
304     p = pathx_aug_parse(aug, aug->origin, NULL, AUGEAS_CONTEXT, true);
305     ERR_BAIL(aug);
306
307     r = pathx_find_one(p, &match);
308     ERR_THROW(r > 1, aug, AUG_EMMATCH,
309               "There are %d nodes matching %s, expecting one",
310               r, AUGEAS_CONTEXT);
311
312     if (match == NULL || match->value == NULL || *match->value == '\0')
313         goto error;
314
315     /* Clean via augrun's helper to ensure it's valid */
316     ctx_path = cleanpath(match->value);
317     free_pathx(p);
318
319     p = pathx_aug_parse(aug, aug->origin, NULL, ctx_path, true);
320     ERR_BAIL(aug);
321
322     if (pathx_first(p) == NULL) {
323         r = pathx_expand_tree(p, &match);
324         if (r < 0)
325             goto done;
326         r = tree_set_value(match, NULL);
327         if (r < 0)
328             goto done;
329     } else {
330         r = pathx_find_one(p, &match);
331         ERR_THROW(r > 1, aug, AUG_EMMATCH,
332                   "There are %d nodes matching the context %s, expecting one",
333                   r, ctx_path);
334     }
335
336  done:
337     free_pathx(p);
338     return match;
339  error:
340     match = NULL;
341     goto done;
342 }
343
344 struct tree *tree_append(struct tree *parent,
345                          char *label, char *value) {
346     struct tree *result = make_tree(label, value, parent, NULL);
347     if (result != NULL)
348         list_append(parent->children, result);
349     return result;
350 }
351
352 static struct tree *tree_append_s(struct tree *parent,
353                                   const char *l0, char *v) {
354     struct tree *result;
355     char *l;
356
357     if (l0 == NULL) {
358         return NULL;
359     } else {
360       l = strdup(l0);
361     }
362     result = tree_append(parent, l, v);
363     if (result == NULL)
364         free(l);
365     return result;
366 }
367
368 static struct tree *tree_from_transform(struct augeas *aug,
369                                         const char *modname,
370                                         struct transform *xfm) {
371     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
372     struct tree *load = NULL, *txfm = NULL, *t;
373     char *v = NULL;
374     int r;
375
376     ERR_NOMEM(meta == NULL, aug);
377
378     load = tree_child_cr(meta, s_load);
379     ERR_NOMEM(load == NULL, aug);
380
381     if (modname == NULL)
382         modname = "_";
383
384     txfm = tree_append_s(load, modname, NULL);
385     ERR_NOMEM(txfm == NULL, aug);
386
387     r = asprintf(&v, "@%s", modname);
388     ERR_NOMEM(r < 0, aug);
389
390     t = tree_append_s(txfm, s_lens, v);
391     ERR_NOMEM(t == NULL, aug);
392     v = NULL;
393
394     list_for_each(f, xfm->filter) {
395         const char *l = f->include ? s_incl : s_excl;
396         v = strdup(f->glob->str);
397         ERR_NOMEM(v == NULL, aug);
398         t = tree_append_s(txfm, l, v);
399         ERR_NOMEM(t == NULL, aug);
400     }
401     return txfm;
402  error:
403     free(v);
404     tree_unlink(aug, txfm);
405     return NULL;
406 }
407
408 /* Save user locale and switch to C locale */
409 #if HAVE_USELOCALE
410 static void save_locale(struct augeas *aug) {
411     if (aug->c_locale == NULL) {
412         aug->c_locale = newlocale(LC_ALL_MASK, "C", NULL);
413         ERR_NOMEM(aug->c_locale == NULL, aug);
414     }
415
416     aug->user_locale = uselocale(aug->c_locale);
417  error:
418     return;
419 }
420 #else
421 static void save_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
422 #endif
423
424 #if HAVE_USELOCALE
425 static void restore_locale(struct augeas *aug) {
426     uselocale(aug->user_locale);
427     aug->user_locale = NULL;
428 }
429 #else
430 static void restore_locale(ATTRIBUTE_UNUSED struct augeas *aug) { }
431 #endif
432
433 /* Clean up old error messages every time we enter through the public
434  * API. Since we make internal calls through the public API, we keep a
435  * count of how many times a public API call was made, and only reset when
436  * that count is 0. That requires that all public functions enclose their
437  * work within a matching pair of api_entry/api_exit calls.
438  */
439 void api_entry(const struct augeas *aug) {
440     struct error *err = ((struct augeas *) aug)->error;
441
442     ((struct augeas *) aug)->api_entries += 1;
443
444     if (aug->api_entries > 1)
445         return;
446
447     reset_error(err);
448     save_locale((struct augeas *) aug);
449 }
450
451 void api_exit(const struct augeas *aug) {
452     assert(aug->api_entries > 0);
453     ((struct augeas *) aug)->api_entries -= 1;
454     if (aug->api_entries == 0) {
455         store_pathx_error(aug);
456         restore_locale((struct augeas *) aug);
457     }
458 }
459
460 static int init_root(struct augeas *aug, const char *root0) {
461     if (root0 == NULL)
462         root0 = getenv(AUGEAS_ROOT_ENV);
463     if (root0 == NULL || root0[0] == '\0')
464         root0 = "/";
465
466     aug->root = strdup(root0);
467     if (aug->root == NULL)
468         return -1;
469
470     if (aug->root[strlen(aug->root)-1] != SEP) {
471         if (REALLOC_N(aug->root, strlen(aug->root) + 2) < 0)
472             return -1;
473         strcat((char *) aug->root, "/");
474     }
475     return 0;
476 }
477
478 static int init_loadpath(struct augeas *aug, const char *loadpath) {
479     int r;
480
481     aug->modpathz = NULL;
482     aug->nmodpath = 0;
483     if (loadpath != NULL) {
484         r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
485                          loadpath, PATH_SEP_CHAR);
486         if (r != 0)
487             return -1;
488     }
489     char *env = getenv(AUGEAS_LENS_ENV);
490     if (env != NULL) {
491         r = argz_add_sep(&aug->modpathz, &aug->nmodpath,
492                          env, PATH_SEP_CHAR);
493         if (r != 0)
494             return -1;
495     }
496     if (!(aug->flags & AUG_NO_STDINC)) {
497         r = argz_add(&aug->modpathz, &aug->nmodpath, AUGEAS_LENS_DIR);
498         if (r != 0)
499             return -1;
500         r = argz_add(&aug->modpathz, &aug->nmodpath,
501                      AUGEAS_LENS_DIST_DIR);
502         if (r != 0)
503             return -1;
504     }
505     /* Clean up trailing slashes */
506     if (aug->nmodpath > 0) {
507         argz_stringify(aug->modpathz, aug->nmodpath, PATH_SEP_CHAR);
508         char *s, *t;
509         const char *e = aug->modpathz + strlen(aug->modpathz);
510         for (s = aug->modpathz, t = aug->modpathz; s < e; s++) {
511             char *p = s;
512             if (*p == '/') {
513                 while (*p == '/') p += 1;
514                 if (*p == '\0' || *p == PATH_SEP_CHAR)
515                     s = p;
516             }
517             if (t != s)
518                 *t++ = *s;
519             else
520                 t += 1;
521         }
522         if (t != s) {
523             *t = '\0';
524         }
525         s = aug->modpathz;
526         aug->modpathz = NULL;
527         r = argz_create_sep(s, PATH_SEP_CHAR, &aug->modpathz,
528                             &aug->nmodpath);
529         free(s);
530         if (r != 0)
531             return -1;
532     }
533     return 0;
534 }
535
536 static void init_save_mode(struct augeas *aug) {
537     const char *v = AUG_SAVE_OVERWRITE_TEXT;
538
539     if (aug->flags & AUG_SAVE_NEWFILE) {
540         v = AUG_SAVE_NEWFILE_TEXT;
541     } else if (aug->flags & AUG_SAVE_BACKUP) {
542         v = AUG_SAVE_BACKUP_TEXT;
543     } else if (aug->flags & AUG_SAVE_NOOP) {
544         v = AUG_SAVE_NOOP_TEXT;
545     }
546
547     aug_set(aug, AUGEAS_META_SAVE_MODE, v);
548 }
549
550 struct augeas *aug_init(const char *root, const char *loadpath,
551                         unsigned int flags) {
552     struct augeas *result;
553     struct tree *tree_root = make_tree(NULL, NULL, NULL, NULL);
554     int r;
555     bool close_on_error = true;
556
557     if (tree_root == NULL)
558         return NULL;
559
560     if (ALLOC(result) < 0)
561         goto error;
562     if (ALLOC(result->error) < 0)
563         goto error;
564     if (make_ref(result->error->info) < 0)
565         goto error;
566     result->error->info->error = result->error;
567     result->error->info->filename = dup_string("(unknown file)");
568     if (result->error->info->filename == NULL)
569         goto error;
570     result->error->aug = result;
571
572     result->origin = make_tree_origin(tree_root);
573     if (result->origin == NULL) {
574         free_tree(tree_root);
575         goto error;
576     }
577
578     api_entry(result);
579
580     result->flags = flags;
581
582     r = init_root(result, root);
583     ERR_NOMEM(r < 0, result);
584
585     result->origin->children->label = strdup(s_augeas);
586
587     /* We are now initialized enough that we can dare return RESULT even
588      * when we encounter errors if the caller so wishes */
589     close_on_error = !(flags & AUG_NO_ERR_CLOSE);
590
591     r = init_loadpath(result, loadpath);
592     ERR_NOMEM(r < 0, result);
593
594     /* We report the root dir in AUGEAS_META_ROOT, but we only use the
595        value we store internally, to avoid any problems with
596        AUGEAS_META_ROOT getting changed. */
597     aug_set(result, AUGEAS_META_ROOT, result->root);
598     ERR_BAIL(result);
599
600     /* Set the default path context */
601     aug_set(result, AUGEAS_CONTEXT, AUG_CONTEXT_DEFAULT);
602     ERR_BAIL(result);
603
604     for (int i=0; i < ARRAY_CARDINALITY(static_nodes); i++) {
605         aug_set(result, static_nodes[i][0], static_nodes[i][1]);
606         ERR_BAIL(result);
607     }
608
609     init_save_mode(result);
610     ERR_BAIL(result);
611
612     const char *v = (flags & AUG_ENABLE_SPAN) ? AUG_ENABLE : AUG_DISABLE;
613     aug_set(result, AUGEAS_SPAN_OPTION, v);
614     ERR_BAIL(result);
615
616     if (interpreter_init(result) == -1)
617         goto error;
618
619     list_for_each(modl, result->modules) {
620         struct transform *xform = modl->autoload;
621         if (xform == NULL)
622             continue;
623         tree_from_transform(result, modl->name, xform);
624         ERR_BAIL(result);
625     }
626     if (!(result->flags & AUG_NO_LOAD))
627         if (aug_load(result) < 0)
628             goto error;
629
630     api_exit(result);
631     return result;
632
633  error:
634     if (close_on_error) {
635         aug_close(result);
636         result = NULL;
637     }
638     if (result != NULL && result->api_entries > 0)
639         api_exit(result);
640     return result;
641 }
642
643 /* Free one tree node */
644 static void free_tree_node(struct tree *tree) {
645     if (tree == NULL)
646         return;
647
648     if (tree->span != NULL)
649         free_span(tree->span);
650     free(tree->label);
651     free(tree->value);
652     free(tree);
653 }
654
655 /* Only unlink; assume we know TREE is not in the symtab */
656 static int tree_unlink_raw(struct tree *tree) {
657     int result = 0;
658
659     assert (tree->parent != NULL);
660     list_remove(tree, tree->parent->children);
661     tree_mark_dirty(tree->parent);
662     result = free_tree(tree->children) + 1;
663     free_tree_node(tree);
664     return result;
665 }
666
667 int tree_unlink(struct augeas *aug, struct tree *tree) {
668     if (tree == NULL)
669         return 0;
670     pathx_symtab_remove_descendants(aug->symtab, tree);
671     return tree_unlink_raw(tree);
672 }
673
674 void tree_unlink_children(struct augeas *aug, struct tree *tree) {
675     if (tree == NULL)
676         return;
677
678     pathx_symtab_remove_descendants(aug->symtab, tree);
679
680     while (tree->children != NULL)
681         tree_unlink_raw(tree->children);
682 }
683
684 static void tree_mark_files(struct tree *tree) {
685     if (tree_child(tree, "path") != NULL) {
686         tree_mark_dirty(tree);
687     } else {
688         list_for_each(c, tree->children) {
689             tree_mark_files(c);
690         }
691     }
692 }
693
694 static void tree_rm_dirty_files(struct augeas *aug, struct tree *tree) {
695     struct tree *p;
696
697     if (!tree->dirty)
698         return;
699
700     if ((p = tree_child(tree, "path")) != NULL) {
701         tree_unlink(aug, tree_fpath(aug, p->value));
702         tree_unlink(aug, tree);
703     } else {
704         struct tree *c = tree->children;
705         while (c != NULL) {
706             struct tree *next = c->next;
707             tree_rm_dirty_files(aug, c);
708             c = next;
709         }
710     }
711 }
712
713 static void tree_rm_dirty_leaves(struct augeas *aug, struct tree *tree,
714                                  struct tree *protect) {
715     if (! tree->dirty)
716         return;
717
718     struct tree *c = tree->children;
719     while (c != NULL) {
720         struct tree *next = c->next;
721         tree_rm_dirty_leaves(aug, c, protect);
722         c = next;
723     }
724
725     if (tree != protect && tree->children == NULL)
726         tree_unlink(aug, tree);
727 }
728
729 int aug_load(struct augeas *aug) {
730     const char *option = NULL;
731     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
732     struct tree *meta_files = tree_child_cr(meta, s_files);
733     struct tree *files = tree_child_cr(aug->origin, s_files);
734     struct tree *load = tree_child_cr(meta, s_load);
735     struct tree *vars = tree_child_cr(meta, s_vars);
736
737     api_entry(aug);
738
739     ERR_NOMEM(load == NULL, aug);
740
741     /* To avoid unnecessary loads of files, we reload an existing file in
742      * several steps:
743      * (1) mark all file nodes under /augeas/files as dirty (and only those)
744      * (2) process all files matched by a lens; we check (in
745      *     transform_load) if the file has been modified. If it has, we
746      *     reparse it. Either way, we clear the dirty flag. We also need to
747      *     reread the file if part or all of it has been modified in the
748      *     tree but not been saved yet
749      * (3) remove all files from the tree that still have a dirty entry
750      *     under /augeas/files. Those files are not processed by any lens
751      *     anymore
752      * (4) Remove entries from /augeas/files and /files that correspond
753      *     to directories without any files of interest
754      */
755
756     /* update flags according to option value */
757     if (aug_get(aug, AUGEAS_SPAN_OPTION, &option) == 1) {
758         if (strcmp(option, AUG_ENABLE) == 0) {
759             aug->flags |= AUG_ENABLE_SPAN;
760         } else {
761             aug->flags &= ~AUG_ENABLE_SPAN;
762         }
763     }
764
765     tree_clean(meta_files);
766     tree_mark_files(meta_files);
767
768     list_for_each(xfm, load->children) {
769         if (transform_validate(aug, xfm) == 0)
770             transform_load(aug, xfm);
771     }
772
773     /* This makes it possible to spot 'directories' that are now empty
774      * because we removed their file contents */
775     tree_clean(files);
776
777     tree_rm_dirty_files(aug, meta_files);
778     tree_rm_dirty_leaves(aug, meta_files, meta_files);
779     tree_rm_dirty_leaves(aug, files, files);
780
781     tree_clean(aug->origin);
782
783     list_for_each(v, vars->children) {
784         aug_defvar(aug, v->label, v->value);
785         ERR_BAIL(aug);
786     }
787
788     api_exit(aug);
789     return 0;
790  error:
791     api_exit(aug);
792     return -1;
793 }
794
795 static int find_one_node(struct pathx *p, struct tree **match) {
796     struct error *err = err_of_pathx(p);
797     int r = pathx_find_one(p, match);
798
799     if (r == 1)
800         return 0;
801
802     if (r == 0) {
803         report_error(err, AUG_ENOMATCH, NULL);
804     } else {
805         /* r > 1 */
806         report_error(err, AUG_EMMATCH, NULL);
807     }
808
809     return -1;
810 }
811
812 int aug_get(const struct augeas *aug, const char *path, const char **value) {
813     struct pathx *p = NULL;
814     struct tree *match;
815     int r;
816
817     if (value != NULL)
818         *value = NULL;
819
820     api_entry(aug);
821
822     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
823     ERR_BAIL(aug);
824
825     r = pathx_find_one(p, &match);
826     ERR_BAIL(aug);
827     ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
828               r, path);
829
830     if (r == 1 && value != NULL)
831         *value = match->value;
832     free_pathx(p);
833
834     api_exit(aug);
835     return r;
836  error:
837     free_pathx(p);
838     api_exit(aug);
839     return -1;
840 }
841
842 int aug_label(const struct augeas *aug, const char *path, const char **label) {
843     struct pathx *p = NULL;
844     struct tree *match;
845     int r;
846
847     api_entry(aug);
848
849     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
850     ERR_BAIL(aug);
851
852     if (label != NULL)
853         *label = NULL;
854
855     r = pathx_find_one(p, &match);
856     ERR_BAIL(aug);
857     ERR_THROW(r > 1, aug, AUG_EMMATCH, "There are %d nodes matching %s",
858               r, path);
859
860     if (r == 1 && label != NULL)
861         *label = match->label;
862     free_pathx(p);
863
864     api_exit(aug);
865     return r;
866  error:
867     free_pathx(p);
868     api_exit(aug);
869     return -1;
870 }
871
872 static void record_var_meta(struct augeas *aug, const char *name,
873                             const char *expr) {
874     /* Record the definition of the variable */
875     struct tree *tree = tree_path_cr(aug->origin, 2, s_augeas, s_vars);
876     ERR_NOMEM(tree == NULL, aug);
877     if (expr == NULL) {
878         tree_unlink(aug, tree_child(tree, name));
879     } else {
880         tree = tree_child_cr(tree, name);
881         ERR_NOMEM(tree == NULL, aug);
882         tree_set_value(tree, expr);
883     }
884  error:
885     return;
886 }
887
888 int aug_defvar(augeas *aug, const char *name, const char *expr) {
889     struct pathx *p = NULL;
890     int result = -1;
891
892     api_entry(aug);
893
894     if (expr == NULL) {
895         result = pathx_symtab_undefine(&(aug->symtab), name);
896     } else {
897         p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
898         ERR_BAIL(aug);
899         result = pathx_symtab_define(&(aug->symtab), name, p);
900     }
901     ERR_BAIL(aug);
902
903     record_var_meta(aug, name, expr);
904     ERR_BAIL(aug);
905  error:
906     free_pathx(p);
907     api_exit(aug);
908     return result;
909 }
910
911 int aug_defnode(augeas *aug, const char *name, const char *expr,
912                 const char *value, int *created) {
913     struct pathx *p;
914     int result = -1;
915     int r, cr;
916     struct tree *tree;
917
918     api_entry(aug);
919
920     if (expr == NULL)
921         goto error;
922     if (created == NULL)
923         created = &cr;
924
925     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), expr, false);
926     ERR_BAIL(aug);
927
928     if (pathx_first(p) == NULL) {
929         r = pathx_expand_tree(p, &tree);
930         if (r < 0)
931             goto done;
932         *created = 1;
933     } else {
934         *created = 0;
935     }
936
937     if (*created) {
938         r = tree_set_value(tree, value);
939         if (r < 0)
940             goto done;
941         result = pathx_symtab_assign_tree(&(aug->symtab), name, tree);
942         char *e = path_of_tree(tree);
943         ERR_NOMEM(e == NULL, aug)
944         record_var_meta(aug, name, e);
945         free(e);
946         ERR_BAIL(aug);
947     } else {
948         result = pathx_symtab_define(&(aug->symtab), name, p);
949         record_var_meta(aug, name, expr);
950         ERR_BAIL(aug);
951     }
952
953  done:
954     free_pathx(p);
955     api_exit(aug);
956     return result;
957  error:
958     api_exit(aug);
959     return -1;
960 }
961
962 struct tree *tree_set(struct pathx *p, const char *value) {
963     struct tree *tree;
964     int r;
965
966     r = pathx_expand_tree(p, &tree);
967     if (r == -1)
968         return NULL;
969
970     r = tree_set_value(tree, value);
971     if (r < 0)
972         return NULL;
973     return tree;
974 }
975
976 int aug_set(struct augeas *aug, const char *path, const char *value) {
977     struct pathx *p;
978     int result;
979
980     api_entry(aug);
981
982     /* Get-out clause, in case context is broken */
983     struct tree *root_ctx = NULL;
984     if (STRNEQ(path, AUGEAS_CONTEXT))
985         root_ctx = tree_root_ctx(aug);
986
987     p = pathx_aug_parse(aug, aug->origin, root_ctx, path, true);
988     ERR_BAIL(aug);
989
990     result = tree_set(p, value) == NULL ? -1 : 0;
991     free_pathx(p);
992
993     api_exit(aug);
994     return result;
995  error:
996     api_exit(aug);
997     return -1;
998 }
999
1000 int aug_setm(struct augeas *aug, const char *base,
1001              const char *sub, const char *value) {
1002     struct pathx *bx = NULL, *sx = NULL;
1003     struct tree *bt, *st;
1004     int result, r;
1005
1006     api_entry(aug);
1007
1008     bx = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), base, true);
1009     ERR_BAIL(aug);
1010
1011     if (sub != NULL && STREQ(sub, "."))
1012         sub = NULL;
1013
1014     result = 0;
1015     for (bt = pathx_first(bx); bt != NULL; bt = pathx_next(bx)) {
1016         if (sub != NULL) {
1017             /* Handle subnodes of BT */
1018             sx = pathx_aug_parse(aug, bt, NULL, sub, true);
1019             ERR_BAIL(aug);
1020             if (pathx_first(sx) != NULL) {
1021                 /* Change existing subnodes matching SUB */
1022                 for (st = pathx_first(sx); st != NULL; st = pathx_next(sx)) {
1023                     r = tree_set_value(st, value);
1024                     ERR_NOMEM(r < 0, aug);
1025                     result += 1;
1026                 }
1027             } else {
1028                 /* Create a new subnode matching SUB */
1029                 r = pathx_expand_tree(sx, &st);
1030                 if (r == -1)
1031                     goto error;
1032                 r = tree_set_value(st, value);
1033                 ERR_NOMEM(r < 0, aug);
1034                 result += 1;
1035             }
1036             free_pathx(sx);
1037             sx = NULL;
1038         } else {
1039             /* Set nodes matching BT directly */
1040             r = tree_set_value(bt, value);
1041             ERR_NOMEM(r < 0, aug);
1042             result += 1;
1043         }
1044     }
1045
1046  done:
1047     api_exit(aug);
1048     return result;
1049  error:
1050     result = -1;
1051     goto done;
1052 }
1053
1054 int tree_insert(struct pathx *p, const char *label, int before) {
1055     struct tree *new = NULL, *match;
1056
1057     if (strchr(label, SEP) != NULL)
1058         return -1;
1059
1060     if (find_one_node(p, &match) < 0)
1061         goto error;
1062
1063     new = make_tree(strdup(label), NULL, match->parent, NULL);
1064     if (new == NULL || new->label == NULL)
1065         goto error;
1066
1067     if (before) {
1068         list_insert_before(new, match, new->parent->children);
1069     } else {
1070         new->next = match->next;
1071         match->next = new;
1072     }
1073     return 0;
1074  error:
1075     free_tree(new);
1076     return -1;
1077 }
1078
1079 int aug_insert(struct augeas *aug, const char *path, const char *label,
1080                int before) {
1081     struct pathx *p = NULL;
1082     int result = -1;
1083
1084     api_entry(aug);
1085
1086     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1087     ERR_BAIL(aug);
1088
1089     result = tree_insert(p, label, before);
1090  error:
1091     free_pathx(p);
1092     api_exit(aug);
1093     return result;
1094 }
1095
1096 struct tree *make_tree(char *label, char *value, struct tree *parent,
1097                        struct tree *children) {
1098     struct tree *tree;
1099     if (ALLOC(tree) < 0)
1100         return NULL;
1101
1102     tree->label = label;
1103     tree->value = value;
1104     tree->parent = parent;
1105     tree->children = children;
1106     list_for_each(c, tree->children)
1107         c->parent = tree;
1108     if (parent != NULL)
1109         tree_mark_dirty(tree);
1110     else
1111         tree->dirty = 1;
1112     return tree;
1113 }
1114
1115 struct tree *make_tree_origin(struct tree *root) {
1116     struct tree *origin = NULL;
1117
1118     origin = make_tree(NULL, NULL, NULL, root);
1119     if (origin == NULL)
1120         return NULL;
1121
1122     origin->parent = origin;
1123     return origin;
1124 }
1125
1126 /* Recursively free the whole tree TREE and all its siblings */
1127 int free_tree(struct tree *tree) {
1128     int cnt = 0;
1129
1130     while (tree != NULL) {
1131         struct tree *del = tree;
1132         tree = del->next;
1133         cnt += free_tree(del->children);
1134         free_tree_node(del);
1135         cnt += 1;
1136     }
1137
1138     return cnt;
1139 }
1140
1141 int tree_rm(struct pathx *p) {
1142     struct tree *tree, **del;
1143     int cnt = 0, ndel = 0, i;
1144
1145     /* set ndel to the number of trees we could possibly delete */
1146     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1147         if (! TREE_HIDDEN(tree))
1148             ndel += 1;
1149     }
1150
1151     if (ndel == 0)
1152         return 0;
1153
1154     if (ALLOC_N(del, ndel) < 0) {
1155         free(del);
1156         return -1;
1157     }
1158
1159     for (i = 0, tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1160         if (TREE_HIDDEN(tree))
1161             continue;
1162         pathx_symtab_remove_descendants(pathx_get_symtab(p), tree);
1163         /* Collect the tree nodes that actually need to be deleted in
1164            del. Mark the root of every subtree we are going to free by
1165            setting tree->added. Only add a node to del if none of its
1166            ancestors would have been freed by the time we get to freeing
1167            that node; this avoids double frees for situations where the
1168            path expression matches both /node and /node/child as unlinking
1169            /node implicitly unlinks /node/child */
1170         int live = 1;
1171         for (struct tree *t = tree; live && ! ROOT_P(t); t = t->parent) {
1172             if (t->added)
1173                 live = 0;
1174         }
1175         if (live) {
1176             del[i] = tree;
1177             i += 1;
1178             tree->added = 1;
1179         }
1180     }
1181     /* ndel now means: the number of trees we are actually going to delete */
1182     ndel = i;
1183
1184     for (i = 0; i < ndel; i++) {
1185         if (del[i] != NULL) {
1186             cnt += tree_unlink_raw(del[i]);
1187         }
1188     }
1189     free(del);
1190
1191     return cnt;
1192 }
1193
1194 int aug_rm(struct augeas *aug, const char *path) {
1195     struct pathx *p = NULL;
1196     int result;
1197
1198     api_entry(aug);
1199
1200     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1201     ERR_BAIL(aug);
1202
1203     result = tree_rm(p);
1204     free_pathx(p);
1205     ERR_BAIL(aug);
1206
1207     api_exit(aug);
1208     return result;
1209  error:
1210     api_exit(aug);
1211     return -1;
1212 }
1213
1214 int aug_span(struct augeas *aug, const char *path, char **filename,
1215         uint *label_start, uint *label_end, uint *value_start, uint *value_end,
1216         uint *span_start, uint *span_end) {
1217     struct pathx *p = NULL;
1218     int result = -1;
1219     struct tree *tree = NULL;
1220     struct span *span;
1221
1222     api_entry(aug);
1223
1224     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1225     ERR_BAIL(aug);
1226
1227     tree = pathx_first(p);
1228     ERR_BAIL(aug);
1229
1230     ERR_THROW(tree == NULL, aug, AUG_ENOMATCH, "No node matching %s", path);
1231     ERR_THROW(tree->span == NULL, aug, AUG_ENOSPAN, "No span info for %s", path);
1232     ERR_THROW(pathx_next(p) != NULL, aug, AUG_EMMATCH, "Multiple nodes match %s", path);
1233
1234     span = tree->span;
1235
1236     if (label_start != NULL)
1237         *label_start = span->label_start;
1238
1239     if (label_end != NULL)
1240         *label_end = span->label_end;
1241
1242     if (value_start != NULL)
1243         *value_start = span->value_start;
1244
1245     if (value_end != NULL)
1246         *value_end = span->value_end;
1247
1248     if (span_start != NULL)
1249         *span_start = span->span_start;
1250
1251     if (span_end != NULL)
1252         *span_end = span->span_end;
1253
1254     /* We are safer here, make sure we have a filename */
1255     if (filename != NULL) {
1256         if (span->filename == NULL || span->filename->str == NULL) {
1257             *filename = strdup("");
1258         } else {
1259             *filename = strdup(span->filename->str);
1260         }
1261         ERR_NOMEM(*filename == NULL, aug);
1262     }
1263
1264     result = 0;
1265  error:
1266     free_pathx(p);
1267     api_exit(aug);
1268     return result;
1269 }
1270
1271 int aug_mv(struct augeas *aug, const char *src, const char *dst) {
1272     struct pathx *s = NULL, *d = NULL;
1273     struct tree *ts, *td, *t;
1274     int r, ret;
1275
1276     api_entry(aug);
1277
1278     ret = -1;
1279     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1280     ERR_BAIL(aug);
1281
1282     d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1283     ERR_BAIL(aug);
1284
1285     r = find_one_node(s, &ts);
1286     if (r < 0)
1287         goto error;
1288
1289     r = pathx_expand_tree(d, &td);
1290     if (r == -1)
1291         goto error;
1292
1293     /* Don't move SRC into its own descendent */
1294     t = td;
1295     do {
1296         ERR_THROW(t == ts, aug, AUG_EMVDESC,
1297                   "destination %s is a descendant of %s", dst, src);
1298         t = t->parent;
1299     } while (t != aug->origin);
1300
1301     free_tree(td->children);
1302
1303     td->children = ts->children;
1304     list_for_each(c, td->children) {
1305         c->parent = td;
1306     }
1307     free(td->value);
1308     td->value = ts->value;
1309
1310     ts->value = NULL;
1311     ts->children = NULL;
1312
1313     tree_unlink(aug, ts);
1314     tree_mark_dirty(td);
1315
1316     ret = 0;
1317  error:
1318     free_pathx(s);
1319     free_pathx(d);
1320     api_exit(aug);
1321     return ret;
1322 }
1323
1324 static void tree_copy_rec(struct tree *src, struct tree *dst) {
1325   struct tree *n;
1326   char *value;
1327
1328   list_for_each(c, src->children) {
1329     value = c->value == NULL ? NULL : strdup(c->value);
1330     n = tree_append_s(dst, c->label, value);
1331     tree_copy_rec(c, n);
1332   }
1333 }
1334
1335 int aug_cp(struct augeas *aug, const char *src, const char *dst) {
1336     struct pathx *s = NULL, *d = NULL;
1337     struct tree *ts, *td, *t;
1338     int r, ret;
1339
1340     api_entry(aug);
1341
1342     ret = -1;
1343     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1344     ERR_BAIL(aug);
1345
1346     d = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), dst, true);
1347     ERR_BAIL(aug);
1348
1349     r = find_one_node(s, &ts);
1350     if (r < 0)
1351         goto error;
1352
1353     r = pathx_expand_tree(d, &td);
1354     if (r == -1)
1355         goto error;
1356
1357     /* Don't copy SRC into its own descendent */
1358     t = td;
1359     do {
1360         ERR_THROW(t == ts, aug, AUG_ECPDESC,
1361                   "destination %s is a descendant of %s", dst, src);
1362         t = t->parent;
1363     } while (t != aug->origin);
1364
1365     tree_set_value(td, ts->value);
1366     free_tree(td->children);
1367     td->children = NULL;
1368     tree_copy_rec(ts, td);
1369     tree_mark_dirty(td);
1370
1371     ret = 0;
1372  error:
1373     free_pathx(s);
1374     free_pathx(d);
1375     api_exit(aug);
1376     return ret;
1377 }
1378
1379 int aug_rename(struct augeas *aug, const char *src, const char *lbl) {
1380     struct pathx *s = NULL;
1381     struct tree *ts;
1382     int ret;
1383     int count = 0;
1384
1385     api_entry(aug);
1386
1387     ret = -1;
1388     ERR_THROW(strchr(lbl, '/') != NULL, aug, AUG_ELABEL,
1389               "Label %s contains a /", lbl);
1390
1391     s = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), src, true);
1392     ERR_BAIL(aug);
1393
1394     for (ts = pathx_first(s); ts != NULL; ts = pathx_next(s)) {
1395         free(ts->label);
1396         ts->label = strdup(lbl);
1397         tree_mark_dirty(ts);
1398         count ++;
1399     }
1400
1401     free_pathx(s);
1402     api_exit(aug);
1403     return count;
1404  error:
1405     free_pathx(s);
1406     api_exit(aug);
1407     return ret;
1408 }
1409
1410 int aug_match(const struct augeas *aug, const char *pathin, char ***matches) {
1411     struct pathx *p = NULL;
1412     struct tree *tree;
1413     int cnt = 0;
1414
1415     api_entry(aug);
1416
1417     if (matches != NULL)
1418         *matches = NULL;
1419
1420     if (STREQ(pathin, "/")) {
1421         pathin = "/*";
1422     }
1423
1424     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1425     ERR_BAIL(aug);
1426
1427     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1428         if (! TREE_HIDDEN(tree))
1429             cnt += 1;
1430     }
1431     ERR_BAIL(aug);
1432
1433     if (matches == NULL)
1434         goto done;
1435
1436     if (ALLOC_N(*matches, cnt) < 0)
1437         goto error;
1438
1439     int i = 0;
1440     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1441         if (TREE_HIDDEN(tree))
1442             continue;
1443         (*matches)[i] = path_of_tree(tree);
1444         if ((*matches)[i] == NULL) {
1445             goto error;
1446         }
1447         i += 1;
1448     }
1449     ERR_BAIL(aug);
1450  done:
1451     free_pathx(p);
1452     api_exit(aug);
1453     return cnt;
1454
1455  error:
1456     if (matches != NULL) {
1457         if (*matches != NULL) {
1458             for (i=0; i < cnt; i++)
1459                 free((*matches)[i]);
1460             free(*matches);
1461         }
1462     }
1463     free_pathx(p);
1464     api_exit(aug);
1465     return -1;
1466 }
1467
1468 static int tree_save(struct augeas *aug, struct tree *tree,
1469                      const char *path) {
1470     int result = 0;
1471     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1472     struct tree *load = tree_child_cr(meta, s_load);
1473
1474     // FIXME: We need to detect subtrees that aren't saved by anything
1475
1476     if (load == NULL)
1477         return -1;
1478
1479     list_for_each(t, tree) {
1480         if (t->dirty) {
1481             char *tpath = NULL;
1482             struct tree *transform = NULL;
1483             if (asprintf(&tpath, "%s/%s", path, t->label) == -1) {
1484                 result = -1;
1485                 continue;
1486             }
1487             list_for_each(xfm, load->children) {
1488                 if (transform_applies(xfm, tpath)) {
1489                     if (transform == NULL || transform == xfm) {
1490                         transform = xfm;
1491                     } else {
1492                         const char *filename =
1493                             tpath + strlen(AUGEAS_FILES_TREE) + 1;
1494                         transform_file_error(aug, "mxfm_save", filename,
1495                            "Lenses %s and %s could be used to save this file",
1496                                              xfm_lens_name(transform),
1497                                              xfm_lens_name(xfm));
1498                         ERR_REPORT(aug, AUG_EMXFM,
1499                                    "Path %s transformable by lens %s and %s",
1500                                    tpath,
1501                                    xfm_lens_name(transform),
1502                                    xfm_lens_name(xfm));
1503                         result = -1;
1504                     }
1505                 }
1506             }
1507             if (transform != NULL) {
1508                 int r = transform_save(aug, transform, tpath, t);
1509                 if (r == -1)
1510                     result = -1;
1511             } else {
1512                 if (tree_save(aug, t->children, tpath) == -1)
1513                     result = -1;
1514             }
1515             free(tpath);
1516         }
1517     }
1518     return result;
1519 }
1520
1521 /* Reset the flags based on what is set in the tree. */
1522 static int update_save_flags(struct augeas *aug) {
1523     const char *savemode ;
1524
1525     aug_get(aug, AUGEAS_META_SAVE_MODE, &savemode);
1526     if (savemode == NULL)
1527         return -1;
1528
1529     aug->flags &= ~(AUG_SAVE_BACKUP|AUG_SAVE_NEWFILE|AUG_SAVE_NOOP);
1530     if (STREQ(savemode, AUG_SAVE_NEWFILE_TEXT)) {
1531         aug->flags |= AUG_SAVE_NEWFILE;
1532     } else if (STREQ(savemode, AUG_SAVE_BACKUP_TEXT)) {
1533         aug->flags |= AUG_SAVE_BACKUP;
1534     } else if (STREQ(savemode, AUG_SAVE_NOOP_TEXT)) {
1535         aug->flags |= AUG_SAVE_NOOP ;
1536     } else if (STRNEQ(savemode, AUG_SAVE_OVERWRITE_TEXT)) {
1537         return -1;
1538     }
1539
1540     return 0;
1541 }
1542
1543 static int unlink_removed_files(struct augeas *aug,
1544                                 struct tree *files, struct tree *meta) {
1545     /* Find all nodes that correspond to a file and might have to be
1546      * unlinked. A node corresponds to a file if it has a child labelled
1547      * 'path', and we only consider it if there are no errors associated
1548      * with it */
1549     static const char *const file_nodes =
1550         "descendant-or-self::*[path][count(error) = 0]";
1551
1552     int result = 0;
1553
1554     if (! files->dirty)
1555         return 0;
1556
1557     for (struct tree *tm = meta->children; tm != NULL;) {
1558         struct tree *tf = tree_child(files, tm->label);
1559         struct tree *next = tm->next;
1560         if (tf == NULL) {
1561             /* Unlink all files in tm */
1562             struct pathx *px = NULL;
1563             if (pathx_parse(tm, err_of_aug(aug), file_nodes, true,
1564                             aug->symtab, NULL, &px) != PATHX_NOERROR) {
1565                 result = -1;
1566                 continue;
1567             }
1568             for (struct tree *t = pathx_first(px);
1569                  t != NULL;
1570                  t = pathx_next(px)) {
1571                 if (remove_file(aug, t) < 0)
1572                     result = -1;
1573             }
1574             free_pathx(px);
1575         } else if (tf->dirty && ! tree_child(tm, "path")) {
1576             if (unlink_removed_files(aug, tf, tm) < 0)
1577                 result = -1;
1578         }
1579         tm = next;
1580     }
1581     return result;
1582 }
1583
1584 int aug_save(struct augeas *aug) {
1585     int ret = 0;
1586     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1587     struct tree *meta_files = tree_child_cr(meta, s_files);
1588     struct tree *files = tree_child_cr(aug->origin, s_files);
1589     struct tree *load = tree_child_cr(meta, s_load);
1590
1591     api_entry(aug);
1592
1593     if (update_save_flags(aug) < 0)
1594         goto error;
1595
1596     if (files == NULL || meta == NULL || load == NULL)
1597         goto error;
1598
1599     aug_rm(aug, AUGEAS_EVENTS_SAVED);
1600
1601     list_for_each(xfm, load->children)
1602         transform_validate(aug, xfm);
1603
1604     if (files->dirty) {
1605         if (tree_save(aug, files->children, AUGEAS_FILES_TREE) == -1)
1606             ret = -1;
1607
1608         /* Remove files whose entire subtree was removed. */
1609         if (meta_files != NULL) {
1610             if (unlink_removed_files(aug, files, meta_files) < 0)
1611                 ret = -1;
1612         }
1613     }
1614     if (!(aug->flags & AUG_SAVE_NOOP)) {
1615         tree_clean(aug->origin);
1616     }
1617
1618     api_exit(aug);
1619     return ret;
1620  error:
1621     api_exit(aug);
1622     return -1;
1623 }
1624
1625 static int print_one(FILE *out, const char *path, const char *value) {
1626     int r;
1627
1628     r = fprintf(out, "%s", path);
1629     if (r < 0)
1630         return -1;
1631     if (value != NULL) {
1632         char *val = escape(value, -1, STR_ESCAPES);
1633         r = fprintf(out, " = \"%s\"", val);
1634         free(val);
1635         if (r < 0)
1636             return -1;
1637     }
1638     r = fputc('\n', out);
1639     if (r == EOF)
1640         return -1;
1641     return 0;
1642 }
1643
1644 /* PATH is the path up to TREE's parent */
1645 static int print_rec(FILE *out, struct tree *start, const char *ppath,
1646                      int pr_hidden) {
1647     int r;
1648     char *path = NULL;
1649
1650     list_for_each(tree, start) {
1651         if (TREE_HIDDEN(tree) && ! pr_hidden)
1652             continue;
1653
1654         path = path_expand(tree, ppath);
1655         if (path == NULL)
1656             goto error;
1657
1658         r = print_one(out, path, tree->value);
1659         if (r < 0)
1660             goto error;
1661         r = print_rec(out, tree->children, path, pr_hidden);
1662         free(path);
1663         path = NULL;
1664         if (r < 0)
1665             goto error;
1666     }
1667     return 0;
1668  error:
1669     free(path);
1670     return -1;
1671 }
1672
1673 static int print_tree(FILE *out, struct pathx *p, int pr_hidden) {
1674     char *path = NULL;
1675     struct tree *tree;
1676     int r;
1677
1678     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1679         if (TREE_HIDDEN(tree) && ! pr_hidden)
1680             continue;
1681
1682         path = path_of_tree(tree);
1683         if (path == NULL)
1684             goto error;
1685         r = print_one(out, path, tree->value);
1686         if (r < 0)
1687             goto error;
1688         r = print_rec(out, tree->children, path, pr_hidden);
1689         if (r < 0)
1690             goto error;
1691         free(path);
1692         path = NULL;
1693     }
1694     return 0;
1695  error:
1696     free(path);
1697     return -1;
1698 }
1699
1700 int dump_tree(FILE *out, struct tree *tree) {
1701     struct pathx *p;
1702     int result;
1703
1704     if (pathx_parse(tree, NULL, "/*", true, NULL, NULL, &p) != PATHX_NOERROR)
1705         return -1;
1706
1707     result = print_tree(out, p, 1);
1708     free_pathx(p);
1709     return result;
1710 }
1711
1712 static int to_xml_span(xmlNodePtr elem, const char *pfor, int start, int end) {
1713     int r;
1714     char *buf;
1715     xmlAttrPtr prop;
1716     xmlNodePtr span_elem;
1717
1718     span_elem = xmlNewChild(elem, NULL, BAD_CAST "span", NULL);
1719     if (span_elem == NULL)
1720         return -1;
1721
1722     prop = xmlSetProp(span_elem, BAD_CAST "for", BAD_CAST pfor);
1723     if (prop == NULL)
1724         return -1;
1725
1726     /* Format and set the start property */
1727     r = xasprintf(&buf, "%d", start);
1728     if (r < 0)
1729         return -1;
1730
1731     prop = xmlSetProp(span_elem, BAD_CAST "start", BAD_CAST buf);
1732     FREE(buf);
1733     if (prop == NULL)
1734         return -1;
1735
1736     /* Format and set the end property */
1737     r = xasprintf(&buf, "%d", end);
1738     if (r < 0)
1739         return -1;
1740
1741     prop = xmlSetProp(span_elem, BAD_CAST "end", BAD_CAST buf);
1742     FREE(buf);
1743     if (prop == NULL)
1744         return -1;
1745
1746     return 0;
1747 }
1748
1749 static int to_xml_one(xmlNodePtr elem, const struct tree *tree,
1750                       const char *pathin) {
1751     xmlNodePtr value;
1752     xmlAttrPtr prop;
1753     int r;
1754
1755     prop = xmlSetProp(elem, BAD_CAST "label", BAD_CAST tree->label);
1756     if (prop == NULL)
1757         goto error;
1758
1759     if (tree->span) {
1760         struct span *span = tree->span;
1761
1762         prop = xmlSetProp(elem, BAD_CAST "file",
1763                           BAD_CAST span->filename->str);
1764         if (prop == NULL)
1765             goto error;
1766
1767         r = to_xml_span(elem, "label", span->label_start, span->label_end);
1768         if (r < 0)
1769             goto error;
1770
1771         r = to_xml_span(elem, "value", span->value_start, span->value_end);
1772         if (r < 0)
1773             goto error;
1774
1775         r = to_xml_span(elem, "node", span->span_start, span->span_end);
1776         if (r < 0)
1777             goto error;
1778     }
1779
1780     if (pathin != NULL) {
1781         prop = xmlSetProp(elem, BAD_CAST "path", BAD_CAST pathin);
1782         if (prop == NULL)
1783             goto error;
1784     }
1785     if (tree->value != NULL) {
1786         value = xmlNewTextChild(elem, NULL, BAD_CAST "value",
1787                                 BAD_CAST tree->value);
1788         if (value == NULL)
1789             goto error;
1790     }
1791     return 0;
1792  error:
1793     return -1;
1794 }
1795
1796 static int to_xml_rec(xmlNodePtr pnode, struct tree *start,
1797                       const char *pathin) {
1798     int r;
1799     xmlNodePtr elem;
1800
1801     elem = xmlNewChild(pnode, NULL, BAD_CAST "node", NULL);
1802     if (elem == NULL)
1803         goto error;
1804     r = to_xml_one(elem, start, pathin);
1805     if (r < 0)
1806         goto error;
1807
1808     list_for_each(tree, start->children) {
1809         if (TREE_HIDDEN(tree))
1810             continue;
1811         r = to_xml_rec(elem, tree, NULL);
1812         if (r < 0)
1813             goto error;
1814     }
1815
1816     return 0;
1817  error:
1818     return -1;
1819 }
1820
1821 static int tree_to_xml(struct pathx *p, xmlNode **xml, const char *pathin) {
1822     char *path = NULL;
1823     struct tree *tree;
1824     xmlAttrPtr expr;
1825     int r;
1826
1827     *xml = xmlNewNode(NULL, BAD_CAST "augeas");
1828     if (*xml == NULL)
1829         goto error;
1830     expr = xmlSetProp(*xml, BAD_CAST "match", BAD_CAST pathin);
1831     if (expr == NULL)
1832         goto error;
1833
1834     for (tree = pathx_first(p); tree != NULL; tree = pathx_next(p)) {
1835         if (TREE_HIDDEN(tree))
1836             continue;
1837         path = path_of_tree(tree);
1838         if (path == NULL)
1839             goto error;
1840         r = to_xml_rec(*xml, tree, path);
1841         if (r < 0)
1842             goto error;
1843         FREE(path);
1844     }
1845     return 0;
1846  error:
1847     free(path);
1848     xmlFree(*xml);
1849     *xml = NULL;
1850     return -1;
1851 }
1852
1853 int aug_text_store(augeas *aug, const char *lens, const char *node,
1854                    const char *path) {
1855
1856     struct pathx *p;
1857     const char *src;
1858     int result = -1, r;
1859
1860     api_entry(aug);
1861
1862     /* Validate PATH is syntactically correct */
1863     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), path, true);
1864     ERR_BAIL(aug);
1865     free_pathx(p);
1866
1867     r = aug_get(aug, node, &src);
1868     ERR_BAIL(aug);
1869     ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1870               "Source node %s does not exist", node);
1871     ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1872               "Source node %s has a NULL value", node);
1873
1874     result = text_store(aug, lens, path, src);
1875  error:
1876     api_exit(aug);
1877     return result;
1878 }
1879
1880 int aug_text_retrieve(struct augeas *aug, const char *lens,
1881                       const char *node_in, const char *path,
1882                       const char *node_out) {
1883     struct tree *tree = NULL;
1884     const char *src;
1885     char *out = NULL;
1886     struct tree *tree_out;
1887     int r;
1888
1889     api_entry(aug);
1890
1891     tree = tree_find(aug, path);
1892     ERR_BAIL(aug);
1893
1894     r = aug_get(aug, node_in, &src);
1895     ERR_BAIL(aug);
1896     ERR_THROW(r == 0, aug, AUG_ENOMATCH,
1897               "Source node %s does not exist", node_in);
1898     ERR_THROW(src == NULL, aug, AUG_ENOMATCH,
1899               "Source node %s has a NULL value", node_in);
1900
1901     r = text_retrieve(aug, lens, path, tree, src, &out);
1902     if (r < 0)
1903         goto error;
1904
1905     tree_out = tree_find_cr(aug, node_out);
1906     ERR_BAIL(aug);
1907
1908     tree_store_value(tree_out, &out);
1909
1910     api_exit(aug);
1911     return 0;
1912  error:
1913     free(out);
1914     api_exit(aug);
1915     return -1;
1916 }
1917
1918 int aug_to_xml(const struct augeas *aug, const char *pathin,
1919                xmlNode **xmldoc, unsigned int flags) {
1920     struct pathx *p;
1921     int result;
1922
1923     api_entry(aug);
1924
1925     ARG_CHECK(flags != 0, aug, "aug_to_xml: FLAGS must be 0");
1926     ARG_CHECK(xmldoc == NULL, aug, "aug_to_xml: XMLDOC must be non-NULL");
1927
1928     if (pathin == NULL || strlen(pathin) == 0 || strcmp(pathin, "/") == 0) {
1929         pathin = "/*";
1930     }
1931
1932     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
1933     ERR_BAIL(aug);
1934     result = tree_to_xml(p, xmldoc, pathin);
1935     ERR_THROW(result < 0, aug, AUG_ENOMEM, NULL);
1936     free_pathx(p);
1937     api_exit(aug);
1938
1939     return result;
1940  error:
1941     if (xmldoc !=NULL)
1942         *xmldoc = NULL;
1943     api_exit(aug);
1944     return -1;
1945 }
1946
1947 int aug_transform(struct augeas *aug, const char *lens,
1948                   const char *file, int excl) {
1949     struct tree *meta = tree_child_cr(aug->origin, s_augeas);
1950     struct tree *load = tree_child_cr(meta, s_load);
1951
1952     int r = 0, result = -1;
1953     struct tree *xfm = NULL, *lns = NULL, *t = NULL;
1954     const char *filter = NULL;
1955     char *p;
1956     int exists;
1957     char *lensname = NULL, *xfmname = NULL;
1958
1959     api_entry(aug);
1960
1961     ERR_NOMEM(meta == NULL || load == NULL, aug);
1962
1963     ARG_CHECK(STREQ("", lens), aug, "aug_transform: LENS must not be empty");
1964     ARG_CHECK(STREQ("", file), aug, "aug_transform: FILE must not be empty");
1965
1966     if ((p = strrchr(lens, '.'))) {
1967         lensname = strdup(lens);
1968         xfmname = strndup(lens, p - lens);
1969         ERR_NOMEM(lensname == NULL || xfmname == NULL, aug);
1970     } else {
1971         r = xasprintf(&lensname, "%s.lns", lens);
1972         xfmname = strdup(lens);
1973         ERR_NOMEM(r < 0 || xfmname == NULL, aug);
1974     }
1975
1976     xfm = tree_child_cr(load, xfmname);
1977     ERR_NOMEM(xfm == NULL, aug);
1978
1979     lns = tree_child_cr(xfm, s_lens);
1980     ERR_NOMEM(lns == NULL, aug);
1981
1982     tree_store_value(lns, &lensname);
1983
1984     exists = 0;
1985
1986     filter = excl ? s_excl : s_incl;
1987     list_for_each(c, xfm->children) {
1988         if (c->value != NULL && STREQ(c->value, file)
1989             && streqv(c->label, filter)) {
1990             exists = 1;
1991             break;
1992         }
1993     }
1994     if (! exists) {
1995         t = tree_append_s(xfm, filter, NULL);
1996         ERR_NOMEM(t == NULL, aug);
1997         r = tree_set_value(t, file);
1998         ERR_NOMEM(r < 0, aug);
1999     }
2000
2001     result = 0;
2002  error:
2003     free(lensname);
2004     free(xfmname);
2005     api_exit(aug);
2006     return result;
2007 }
2008
2009 int aug_escape_name(augeas *aug, const char *in, char **out) {
2010     int result = -1;
2011
2012     api_entry(aug);
2013     ARG_CHECK(in == NULL, aug, "aug_escape_name: IN must not be NULL");
2014     ARG_CHECK(out == NULL, aug, "aug_escape_name: OUT must not be NULL");
2015
2016     result = pathx_escape_name(in, out);
2017     ERR_NOMEM(result < 0, aug);
2018  error:
2019     api_exit(aug);
2020     return result;
2021 }
2022
2023 int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
2024     struct pathx *p;
2025     int result;
2026
2027     api_entry(aug);
2028
2029     if (pathin == NULL || strlen(pathin) == 0) {
2030         pathin = "/*";
2031     }
2032
2033     p = pathx_aug_parse(aug, aug->origin, tree_root_ctx(aug), pathin, true);
2034     ERR_BAIL(aug);
2035
2036     result = print_tree(out, p, 0);
2037     free_pathx(p);
2038
2039     api_exit(aug);
2040     return result;
2041  error:
2042     api_exit(aug);
2043     return -1;
2044 }
2045
2046 void aug_close(struct augeas *aug) {
2047     if (aug == NULL)
2048         return;
2049
2050     /* There's no point in bothering with api_entry/api_exit here */
2051     free_tree(aug->origin);
2052     unref(aug->modules, module);
2053     if (aug->error->exn != NULL) {
2054         aug->error->exn->ref = 0;
2055         free_value(aug->error->exn);
2056         aug->error->exn = NULL;
2057     }
2058     free((void *) aug->root);
2059     free(aug->modpathz);
2060     free_symtab(aug->symtab);
2061     unref(aug->error->info, info);
2062     free(aug->error->details);
2063     free(aug->error);
2064     free(aug);
2065 }
2066
2067 int __aug_load_module_file(struct augeas *aug, const char *filename) {
2068     api_entry(aug);
2069     int r = load_module_file(aug, filename, NULL);
2070     api_exit(aug);
2071     return r;
2072 }
2073
2074 int tree_equal(const struct tree *t1, const struct tree *t2) {
2075     while (t1 != NULL && t2 != NULL) {
2076         if (!streqv(t1->label, t2->label))
2077             return 0;
2078         if (!streqv(t1->value, t2->value))
2079             return 0;
2080         if (! tree_equal(t1->children, t2->children))
2081             return 0;
2082         t1 = t1->next;
2083         t2 = t2->next;
2084     }
2085     return t1 == t2;
2086 }
2087
2088 /*
2089  * Error reporting API
2090  */
2091 int aug_error(struct augeas *aug) {
2092     return aug->error->code;
2093 }
2094
2095 const char *aug_error_message(struct augeas *aug) {
2096     aug_errcode_t errcode = aug->error->code;
2097
2098     if (errcode >= ARRAY_CARDINALITY(errcodes))
2099         errcode = AUG_EINTERNAL;
2100     return errcodes[errcode];
2101 }
2102
2103 const char *aug_error_minor_message(struct augeas *aug) {
2104     return aug->error->minor_details;
2105 }
2106
2107 const char *aug_error_details(struct augeas *aug) {
2108     return aug->error->details;
2109 }
2110
2111 /*
2112  * Local variables:
2113  *  indent-tabs-mode: nil
2114  *  c-indent-level: 4
2115  *  c-basic-offset: 4
2116  *  tab-width: 4
2117  * End:
2118  */