+static struct uci_package *uci_file_load(struct uci_context *ctx, const char *name)
+{
+ struct uci_package *package = NULL;
+ char *filename;
+ bool confdir;
+ FILE *file = NULL;
+
+ switch (name[0]) {
+ case '.':
+ /* relative path outside of /etc/config */
+ if (name[1] != '/')
+ UCI_THROW(ctx, UCI_ERR_NOTFOUND);
+ /* fall through */
+ case '/':
+ /* absolute path outside of /etc/config */
+ filename = uci_strdup(ctx, name);
+ name = strrchr(name, '/') + 1;
+ confdir = false;
+ break;
+ default:
+ /* config in /etc/config */
+ filename = uci_config_path(ctx, name);
+ confdir = true;
+ break;
+ }
+
+ UCI_TRAP_SAVE(ctx, done);
+ file = uci_open_stream(ctx, filename, SEEK_SET, false, false);
+ ctx->err = 0;
+ UCI_INTERNAL(uci_import, ctx, file, name, &package, true);
+ UCI_TRAP_RESTORE(ctx);
+
+ if (package) {
+ package->path = filename;
+ package->has_delta = confdir;
+ uci_load_delta(ctx, package, false);
+ }
+
+done:
+ uci_close_stream(file);
+ if (ctx->err) {
+ free(filename);
+ UCI_THROW(ctx, ctx->err);
+ }
+ return package;
+}
+
+__private UCI_BACKEND(uci_file_backend, "file",
+ .load = uci_file_load,
+ .commit = uci_file_commit,
+ .list_configs = uci_list_config_files,
+);