X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=file.c;h=d81bbe85995ce3cebc9c2e924698362537b009de;hp=152d175da122a218b0828e8c2814abe19c82e363;hb=818f7b8433ae369c20fc56cccbb55b22043b9024;hpb=f2520c27cd7942dc01d3386b4083b128648343c0 diff --git a/file.c b/file.c index 152d175..d81bbe8 100644 --- a/file.c +++ b/file.c @@ -18,7 +18,6 @@ #define _GNU_SOURCE #include -#include #include #include #include @@ -26,56 +25,6 @@ #include #include -#define LINEBUF 32 -#define LINEBUF_MAX 4096 - -static void uci_parse_error(struct uci_context *ctx, char *pos, char *reason) -{ - struct uci_parse_context *pctx = ctx->pctx; - - pctx->reason = reason; - pctx->byte = pos - pctx->buf; - UCI_THROW(ctx, UCI_ERR_PARSE); -} - -/* - * Fetch a new line from the input stream and resize buffer if necessary - */ -static void uci_getln(struct uci_context *ctx, int offset) -{ - struct uci_parse_context *pctx = ctx->pctx; - char *p; - int ofs; - - if (pctx->buf == NULL) { - pctx->buf = uci_malloc(ctx, LINEBUF); - pctx->bufsz = LINEBUF; - } - - ofs = offset; - do { - p = &pctx->buf[ofs]; - p[ofs] = 0; - - p = fgets(p, pctx->bufsz - ofs, pctx->file); - if (!p || !*p) - return; - - ofs += strlen(p); - if (pctx->buf[ofs - 1] == '\n') { - pctx->line++; - pctx->buf[ofs - 1] = 0; - return; - } - - if (pctx->bufsz > LINEBUF_MAX/2) - uci_parse_error(ctx, p, "line too long"); - - pctx->bufsz *= 2; - pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz); - } while (1); -} - /* * Clean up all extra memory used by the parser and exporter */ @@ -103,6 +52,7 @@ static void uci_file_cleanup(struct uci_context *ctx) free(pctx); } + /* * parse a character escaped by '\' * returns true if the escaped character is to be parsed @@ -619,178 +569,6 @@ error: return 0; } -/* - * open a stream and go to the right position - * - * note: when opening for write and seeking to the beginning of - * the stream, truncate the file - */ -static FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write, bool create) -{ - struct stat statbuf; - FILE *file = NULL; - int fd, ret; - int mode = (write ? O_RDWR : O_RDONLY); - - if (create) - mode |= O_CREAT; - - if (!write && ((stat(filename, &statbuf) < 0) || - ((statbuf.st_mode & S_IFMT) != S_IFREG))) { - UCI_THROW(ctx, UCI_ERR_NOTFOUND); - } - - fd = open(filename, mode, UCI_FILEMODE); - if (fd <= 0) - goto error; - - if (flock(fd, (write ? LOCK_EX : LOCK_SH)) < 0) - goto error; - - ret = lseek(fd, 0, pos); - - if (ret < 0) - goto error; - - file = fdopen(fd, (write ? "w+" : "r")); - if (file) - goto done; - -error: - UCI_THROW(ctx, UCI_ERR_IO); -done: - return file; -} - -static void uci_close_stream(FILE *stream) -{ - int fd; - - if (!stream) - return; - - fd = fileno(stream); - flock(fd, LOCK_UN); - fclose(stream); -} - -static void uci_parse_history_line(struct uci_context *ctx, struct uci_package *p, char *buf) -{ - bool delete = false; - bool rename = false; - char *package = NULL; - char *section = NULL; - char *option = NULL; - char *value = NULL; - - if (buf[0] == '-') { - delete = true; - buf++; - } else if (buf[0] == '@') { - rename = true; - buf++; - } - - UCI_INTERNAL(uci_parse_tuple, ctx, buf, &package, §ion, &option, &value); - if (!package || (strcmp(package, p->e.name) != 0)) - goto error; - if (!uci_validate_name(section)) - goto error; - if (option && !uci_validate_name(option)) - goto error; - if ((rename || !delete) && !uci_validate_name(value)) - goto error; - - if (rename) - UCI_INTERNAL(uci_rename, ctx, p, section, option, value); - else if (delete) - UCI_INTERNAL(uci_delete, ctx, p, section, option); - else - UCI_INTERNAL(uci_set, ctx, p, section, option, value); - - return; -error: - UCI_THROW(ctx, UCI_ERR_PARSE); -} - -static void uci_parse_history(struct uci_context *ctx, FILE *stream, struct uci_package *p) -{ - struct uci_parse_context *pctx; - - /* make sure no memory from previous parse attempts is leaked */ - uci_file_cleanup(ctx); - - pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); - ctx->pctx = pctx; - pctx->file = stream; - - while (!feof(pctx->file)) { - uci_getln(ctx, 0); - if (!pctx->buf[0]) - continue; - - /* - * ignore parse errors in single lines, we want to preserve as much - * history as possible - */ - UCI_TRAP_SAVE(ctx, error); - uci_parse_history_line(ctx, p, pctx->buf); - UCI_TRAP_RESTORE(ctx); -error: - continue; - } - - /* no error happened, we can get rid of the parser context now */ - uci_file_cleanup(ctx); -} - -static void uci_load_history_file(struct uci_context *ctx, struct uci_package *p, char *filename, FILE **f, bool flush) -{ - FILE *stream = NULL; - - UCI_TRAP_SAVE(ctx, done); - stream = uci_open_stream(ctx, filename, SEEK_SET, flush, false); - if (p) - uci_parse_history(ctx, stream, p); - UCI_TRAP_RESTORE(ctx); -done: - if (f) - *f = stream; - else if (stream) - uci_close_stream(stream); -} - -static void uci_load_history(struct uci_context *ctx, struct uci_package *p, bool flush) -{ - struct uci_element *e; - char *filename = NULL; - FILE *f = NULL; - - if (!p->confdir) - return; - - uci_foreach_element(&ctx->history_path, e) { - if ((asprintf(&filename, "%s/%s", e->name, p->e.name) < 0) || !filename) - UCI_THROW(ctx, UCI_ERR_MEM); - - uci_load_history_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_load_history_file(ctx, p, filename, &f, flush); - if (flush && f) { - rewind(f); - ftruncate(fileno(f), 0); - } - if (filename) - free(filename); - uci_close_stream(f); - ctx->errno = 0; -} - static char *uci_config_path(struct uci_context *ctx, const char *name) { @@ -847,64 +625,6 @@ done: return ctx->errno; } -int uci_save(struct uci_context *ctx, struct uci_package *p) -{ - FILE *f = NULL; - char *filename = NULL; - struct uci_element *e, *tmp; - - UCI_HANDLE_ERR(ctx); - UCI_ASSERT(ctx, p != NULL); - - /* - * if the config file was outside of the /etc/config path, - * don't save the history to a file, update the real file - * directly. - * does not modify the uci_package pointer - */ - if (!p->confdir) - return uci_commit(ctx, &p, false); - - if (uci_list_empty(&p->history)) - return 0; - - if ((asprintf(&filename, "%s/%s", ctx->savedir, p->e.name) < 0) || !filename) - UCI_THROW(ctx, UCI_ERR_MEM); - - ctx->errno = 0; - UCI_TRAP_SAVE(ctx, done); - f = uci_open_stream(ctx, filename, SEEK_END, true, true); - UCI_TRAP_RESTORE(ctx); - - uci_foreach_element_safe(&p->history, tmp, e) { - struct uci_history *h = uci_to_history(e); - - if (h->cmd == UCI_CMD_REMOVE) - fprintf(f, "-"); - else if (h->cmd == UCI_CMD_RENAME) - fprintf(f, "@"); - - fprintf(f, "%s.%s", p->e.name, h->section); - if (e->name) - fprintf(f, ".%s", e->name); - - if (h->cmd == UCI_CMD_REMOVE) - fprintf(f, "\n"); - else - fprintf(f, "=%s\n", h->value); - uci_free_history(h); - } - -done: - uci_close_stream(f); - if (filename) - free(filename); - if (ctx->errno) - UCI_THROW(ctx, ctx->errno); - - return 0; -} - int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overwrite) { struct uci_package *p;