- if(strlen(fn) == 0)
- /* User just pressed enter. */
- fn = xstrdup(filename);
- }
-
- if((strchr(fn, '/') == NULL) || (fn[0] != '/'))
- {
- /* The directory is a relative path or a filename. */
- char *p;
-
- directory = get_current_dir_name();
- len = strlen(fn) + strlen(directory) + 2; /* 1 for the / */
- p = xmalloc(len);
- snprintf(p, len, "%s/%s", directory, fn);
- free(fn);
- fn = p;
- }
-
- if(!is_safe_file(fn))
- {
- fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
- "I will not create or overwrite this file.\n"),
- fn);
- return NULL;
- }
-
- if((r = fopen(fn, "w")) == NULL)
- {
- fprintf(stderr, _("Error opening file `%s': %m\n"),
- fn);
- }
-
- free(fn);
- free(directory);
-
- return r;
+
+ FILE *out = fopen(tmpname, "w");
+ if(!out) {
+ logger(mesh, MESHLINK_ERROR, "Failed to write `%s': %s", tmpname, strerror(errno));
+ fclose(in);
+ return false;
+ }
+
+ bool ignore = false;
+
+ while(readline(in, buf, sizeof buf)) {
+ if(ignore) {
+ if(!strncmp(buf, "-----END", 8))
+ ignore = false;
+ } else {
+ if(!strncmp(buf, "-----BEGIN", 10))
+ ignore = true;
+ }
+
+ if(!ignore && !strncmp(buf, key, keylen)) {
+ if(strchr("\t =", buf[keylen])) {
+ continue;
+ }
+ }
+
+ fputs(buf, out);
+ fputc('\n', out);
+ }
+
+ if(ferror(in)) {
+ logger(mesh, MESHLINK_ERROR, "Failed to read `%s': %s", filename, strerror(errno));
+ fclose(in);
+ fclose(out);
+ return false;
+ }
+
+ fclose(in);
+
+ fprintf(out, "%s = %s\n", key, value);
+
+ if(ferror(out)) {
+ logger(mesh, MESHLINK_ERROR, "Failed to write `%s': %s", tmpname, strerror(errno));
+ fclose(out);
+ return false;
+ }
+
+ fclose(out);
+
+#ifdef HAVE_MINGW
+ // We cannot atomically replace files on Windows.
+ char bakname[PATH_MAX];
+ snprintf(bakname, PATH_MAX, "%s.bak", filename);
+ if(rename(tmpname, bakfile) || rename(bakfile, filename)) {
+ rename(bakfile, filename);
+#else
+ if(rename(tmpname, filename)) {
+#endif
+ logger(mesh, MESHLINK_ERROR, "Failed to update `%s': %s", filename, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool append_config_file(meshlink_handle_t *mesh, const char *name, const char *key, const char *value) {
+ char filename[PATH_MAX];
+ snprintf(filename,PATH_MAX, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name);
+
+ FILE *fp = fopen(filename, "a");
+
+ if(!fp) {
+ logger(mesh, MESHLINK_ERROR, "Cannot open config file %s: %s", filename, strerror(errno));
+ return false;
+ }
+
+ // Check if we don't add a duplicate entry
+
+ char entry[MAX_STRING_SIZE];
+ snprintf(entry, sizeof entry, "%s = %s", key, value);
+
+ char buffer[MAX_STRING_SIZE];
+ bool found = false;
+
+ while(readline(fp, buffer, sizeof buffer)) {
+ if(!strcmp(buffer, entry)) {
+ found = true;
+ break;
+ }
+ }
+
+ // If not, append the new entry
+
+ if(!found)
+ fprintf(fp, "%s\n", entry);
+
+ fclose(fp);
+ return true;