Make writing files a bit safer

Especially configuration files.
This commit is contained in:
Přemysl Eric Janouch 2016-01-13 00:19:20 +01:00
parent 9e3cb2b6aa
commit 60dd23ab8f
1 changed files with 19 additions and 3 deletions

View File

@ -3379,11 +3379,11 @@ write_file (const char *filename, const struct str *data, struct error **e)
return false; return false;
} }
errno = 0;
fwrite (data->str, data->len, 1, fp); fwrite (data->str, data->len, 1, fp);
bool success = !ferror (fp) && !fflush (fp) && !fsync (fileno (fp));
fclose (fp); fclose (fp);
if (errno) if (!success)
{ {
error_set (e, "writing to `%s' failed: %s", filename, strerror (errno)); error_set (e, "writing to `%s' failed: %s", filename, strerror (errno));
return false; return false;
@ -3391,6 +3391,22 @@ write_file (const char *filename, const struct str *data, struct error **e)
return true; 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 ---------------------------------------------------- // --- Simple configuration ----------------------------------------------------
// The keys are stripped of surrounding whitespace, the values are not. // 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"); 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); str_free (&path);
return NULL; return NULL;