free the history on package unload
[project/uci.git] / file.c
diff --git a/file.c b/file.c
index a0fe58b..47d9c44 100644 (file)
--- a/file.c
+++ b/file.c
@@ -502,8 +502,18 @@ int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct u
 
        while (!feof(pctx->file)) {
                uci_getln(ctx, 0);
+
+               UCI_TRAP_SAVE(ctx, error);
                if (pctx->buf[0])
                        uci_parse_line(ctx, single);
+               UCI_TRAP_RESTORE(ctx);
+               continue;
+error:
+               if (ctx->flags & UCI_FLAG_PERROR)
+                       uci_perror(ctx, NULL);
+               if ((ctx->errno != UCI_ERR_PARSE) ||
+                       (ctx->flags & UCI_FLAG_STRICT))
+                       UCI_THROW(ctx, ctx->errno);
        }
 
        if (package)
@@ -526,10 +536,16 @@ int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct u
  */
 static FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write)
 {
+       struct stat statbuf;
        FILE *file = NULL;
        int fd, ret;
 
-       fd = open(filename, (write ? O_RDWR | O_CREAT : O_RDONLY));
+       if (!write && ((stat(filename, &statbuf) < 0) ||
+               ((statbuf.st_mode &  S_IFMT) != S_IFREG))) {
+               UCI_THROW(ctx, UCI_ERR_NOTFOUND);
+       }
+
+       fd = open(filename, (write ? O_RDWR | O_CREAT : O_RDONLY), UCI_FILEMODE);
        if (fd <= 0)
                goto error;
 
@@ -580,7 +596,7 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package *
        }
 
        UCI_INTERNAL(uci_parse_tuple, ctx, buf, &package, &section, &option, &value);
-       if (!package || !section || !value)
+       if (!package || !section || (!delete && !value))
                goto error;
        if (strcmp(package, p->e.name) != 0)
                goto error;
@@ -588,10 +604,13 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package *
                goto error;
        if (option && !uci_validate_name(option))
                goto error;
-       if (!delete)
-               UCI_INTERNAL(uci_set, ctx, package, section, option, value);
-       return;
 
+       if (delete)
+               UCI_INTERNAL(uci_del, ctx, p, section, option);
+       else
+               UCI_INTERNAL(uci_set, ctx, p, section, option, value);
+
+       return;
 error:
        UCI_THROW(ctx, UCI_ERR_PARSE);
 }
@@ -642,7 +661,6 @@ done:
 
 int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package)
 {
-       struct stat statbuf;
        char *filename;
        bool confdir;
        FILE *file = NULL;
@@ -672,11 +690,6 @@ int uci_load(struct uci_context *ctx, const char *name, struct uci_package **pac
                break;
        }
 
-       if ((stat(filename, &statbuf) < 0) ||
-               ((statbuf.st_mode &  S_IFMT) != S_IFREG)) {
-               UCI_THROW(ctx, UCI_ERR_NOTFOUND);
-       }
-
        file = uci_open_stream(ctx, filename, SEEK_SET, false);
        ctx->errno = 0;
        UCI_TRAP_SAVE(ctx, done);
@@ -724,13 +737,19 @@ int uci_save(struct uci_context *ctx, struct uci_package *p)
 
        uci_foreach_element_safe(&p->history, tmp, e) {
                struct uci_history *h = uci_to_history(e);
+
                if (h->cmd == UCI_CMD_REMOVE)
                        fprintf(f, "-");
+
                fprintf(f, "%s.%s", p->e.name, h->section);
                if (e->name)
                        fprintf(f, ".%s", e->name);
-               fprintf(f, "=%s\n", h->value);
-               uci_list_del(&e->list);
+
+               if (h->cmd == UCI_CMD_REMOVE)
+                       fprintf(f, "\n");
+               else
+                       fprintf(f, "=%s\n", h->value);
+               uci_free_history(h);
        }
 
 done:
@@ -783,15 +802,17 @@ static inline char *get_filename(char *path)
        return p;
 }
 
-char **uci_list_configs(struct uci_context *ctx)
+int uci_list_configs(struct uci_context *ctx, char ***list)
 {
        char **configs;
        glob_t globbuf;
        int size, i;
        char *buf;
 
+       UCI_HANDLE_ERR(ctx);
+
        if (glob(UCI_CONFDIR "/*", GLOB_MARK, NULL, &globbuf) != 0)
-               return NULL;
+               UCI_THROW(ctx, UCI_ERR_NOTFOUND);
 
        size = sizeof(char *) * (globbuf.gl_pathc + 1);
        for(i = 0; i < globbuf.gl_pathc; i++) {
@@ -817,6 +838,8 @@ char **uci_list_configs(struct uci_context *ctx)
                strcpy(buf, p);
                buf += strlen(buf) + 1;
        }
-       return configs;
+       *list = configs;
+
+       return 0;
 }