diff options
author | Přemysl Janouch <p.janouch@gmail.com> | 2016-01-13 00:19:20 +0100 |
---|---|---|
committer | Přemysl Janouch <p.janouch@gmail.com> | 2016-01-13 00:38:54 +0100 |
commit | 60dd23ab8f5d772bee38200395e54d640499d443 (patch) | |
tree | af3b16395b5ae2575da5407734109833afc73dd5 | |
parent | 9e3cb2b6aa2db3ca0ea6a854fb3f89a163c84235 (diff) | |
download | liberty-60dd23ab8f5d772bee38200395e54d640499d443.tar.gz liberty-60dd23ab8f5d772bee38200395e54d640499d443.tar.xz liberty-60dd23ab8f5d772bee38200395e54d640499d443.zip |
Make writing files a bit safer
Especially configuration files.
-rw-r--r-- | liberty.c | 22 |
1 files changed, 19 insertions, 3 deletions
@@ -3379,11 +3379,11 @@ write_file (const char *filename, const struct str *data, struct error **e) return false; } - errno = 0; fwrite (data->str, data->len, 1, fp); + bool success = !ferror (fp) && !fflush (fp) && !fsync (fileno (fp)); fclose (fp); - if (errno) + if (!success) { error_set (e, "writing to `%s' failed: %s", filename, strerror (errno)); return false; @@ -3391,6 +3391,22 @@ write_file (const char *filename, const struct str *data, struct error **e) return true; } +/// Wrapper for write_file() that makes sure that the new data has been written +/// to disk in its entirety before overriding the old file +static bool +write_file_safe (const char *filename, const struct str *data, struct error **e) +{ + // XXX: ideally we would also open the directory, use *at() versions + // of functions and call fsync() on the directory as appropriate + char *temp = xstrdup_printf ("%s.new", filename); + bool success = write_file (temp, data, e); + if (success && !(success = !rename (temp, filename))) + error_set (e, "could not rename `%s' to `%s': %s", + temp, filename, strerror (errno)); + free (temp); + return success; +} + // --- Simple configuration ---------------------------------------------------- // The keys are stripped of surrounding whitespace, the values are not. @@ -3482,7 +3498,7 @@ write_configuration_file (const char *path_hint, const struct str *data, str_append (&path, "/" PROGRAM_NAME "/" PROGRAM_NAME ".conf"); } - if (!write_file (path.str, data, e)) + if (!write_file_safe (path.str, data, e)) { str_free (&path); return NULL; |