int uci_set_savedir(struct uci_context *ctx, const char *dir)
{
char *sdir;
+ struct uci_element *e, *tmp;
+ volatile bool exists = false;
UCI_HANDLE_ERR(ctx);
UCI_ASSERT(ctx, dir != NULL);
+ /* Move dir to the end of ctx->delta_path */
+ uci_foreach_element_safe(&ctx->delta_path, tmp, e) {
+ if (!strcmp(e->name, dir)) {
+ exists = true;
+ uci_list_del(&e->list);
+ break;
+ }
+ }
+ if (!exists)
+ e = uci_alloc_generic(ctx, UCI_TYPE_PATH, dir, sizeof(struct uci_element));
+ uci_list_add(&ctx->delta_path, &e->list);
+
sdir = uci_strdup(ctx, dir);
if (ctx->savedir != uci_savedir)
free(ctx->savedir);
int uci_add_delta_path(struct uci_context *ctx, const char *dir)
{
struct uci_element *e;
+ struct uci_list *savedir;
UCI_HANDLE_ERR(ctx);
UCI_ASSERT(ctx, dir != NULL);
- if (!strcmp(dir, ctx->savedir))
- return -1;
+
+ /* Duplicate delta path is not allowed */
+ uci_foreach_element(&ctx->delta_path, e) {
+ if (!strcmp(e->name, dir))
+ UCI_THROW(ctx, UCI_ERR_DUPLICATE);
+ }
+
e = uci_alloc_generic(ctx, UCI_TYPE_PATH, dir, sizeof(struct uci_element));
- uci_list_add(&ctx->delta_path, &e->list);
+ /* Keep savedir at the end of ctx->delta_path list */
+ savedir = ctx->delta_path.prev;
+ uci_list_insert(savedir->prev, &e->list);
return 0;
}
int c;
UCI_INTERNAL(uci_parse_argument, ctx, ctx->pctx->file, &str, &arg);
+ if (str && *str) {
+ goto error;
+ }
for (c = 0; c <= __UCI_CMD_LAST; c++) {
if (uci_command_char[c] == *arg)
break;
goto error;
if (ptr->flags & UCI_LOOKUP_EXTENDED)
goto error;
+ if (c != UCI_CMD_REMOVE && !ptr->value) {
+ goto error;
+ }
switch(c) {
case UCI_CMD_REORDER:
case UCI_CMD_LIST_ADD:
if (!ptr->option)
goto error;
+ /* fall through */
case UCI_CMD_LIST_DEL:
if (!ptr->option)
goto error;
static int uci_parse_delta(struct uci_context *ctx, FILE *stream, struct uci_package *p)
{
struct uci_parse_context *pctx;
- int changes = 0;
+ volatile int changes = 0;
/* make sure no memory from previous parse attempts is leaked */
uci_cleanup(ctx);
/* returns the number of changes that were successfully parsed */
static int uci_load_delta_file(struct uci_context *ctx, struct uci_package *p, char *filename, FILE **f, bool flush)
{
- FILE *stream = NULL;
- int changes = 0;
+ FILE *volatile stream = NULL;
+ volatile int changes = 0;
UCI_TRAP_SAVE(ctx, done);
stream = uci_open_stream(ctx, filename, NULL, SEEK_SET, flush, false);
+ UCI_TRAP_RESTORE(ctx);
+
if (p)
changes = uci_parse_delta(ctx, stream, p);
- UCI_TRAP_RESTORE(ctx);
+
done:
if (f)
*f = stream;
- else if (stream)
+ else
uci_close_stream(stream);
return changes;
}
{
struct uci_element *e;
char *filename = NULL;
- FILE *f = NULL;
- int changes = 0;
+ FILE *volatile f = NULL;
+ volatile int changes = 0;
if (!p->has_delta)
return 0;
if ((asprintf(&filename, "%s/%s", e->name, p->e.name) < 0) || !filename)
UCI_THROW(ctx, UCI_ERR_MEM);
- uci_load_delta_file(ctx, p, filename, NULL, false);
+ changes += uci_load_delta_file(ctx, p, filename, NULL, false);
free(filename);
}
if ((asprintf(&filename, "%s/%s", ctx->savedir, p->e.name) < 0) || !filename)
UCI_THROW(ctx, UCI_ERR_MEM);
+ UCI_TRAP_SAVE(ctx, done);
+ f = uci_open_stream(ctx, filename, NULL, SEEK_SET, flush, false);
+ UCI_TRAP_RESTORE(ctx);
- changes = uci_load_delta_file(ctx, p, filename, &f, flush);
if (flush && f && (changes > 0)) {
- rewind(f);
if (ftruncate(fileno(f), 0) < 0) {
+ free(filename);
uci_close_stream(f);
UCI_THROW(ctx, UCI_ERR_IO);
}
}
+
+done:
free(filename);
uci_close_stream(f);
ctx->err = 0;
int uci_revert(struct uci_context *ctx, struct uci_ptr *ptr)
{
- char *package = NULL;
- char *section = NULL;
- char *option = NULL;
+ char *volatile package = NULL;
+ char *volatile section = NULL;
+ char *volatile option = NULL;
UCI_HANDLE_ERR(ctx);
uci_expand_ptr(ctx, ptr, false);
int uci_save(struct uci_context *ctx, struct uci_package *p)
{
- FILE *f = NULL;
+ FILE *volatile f = NULL;
char *filename = NULL;
struct uci_element *e, *tmp;
struct stat statbuf;