From a218e1ded44cc88072f4e1896fdd8bd24f1829ac Mon Sep 17 00:00:00 2001 From: Mitchell Wills Date: Mon, 24 Aug 2015 17:24:30 -0700 Subject: [PATCH] Make sure configuration is saved to storage device Config file is written to a temp file and then it is renamed to the original config file. However, it is possible that the rename operation will be commited to storage while file data will be still in cache causing original config file to be empty or partially written in case of a system reboot without a clean shutdown. Make this less likely to occur by forcing the data to be written to the storage device before renaming the file. Signed-off-by: Dmitry Shmidt --- src/utils/os.h | 7 +++++++ src/utils/os_internal.c | 6 ++++++ src/utils/os_none.c | 6 ++++++ src/utils/os_unix.c | 8 ++++++++ src/utils/os_win32.c | 18 ++++++++++++++++++ wpa_supplicant/config_file.c | 2 ++ 6 files changed, 47 insertions(+) diff --git a/src/utils/os.h b/src/utils/os.h index 2c24631bf..9e496fb65 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -246,6 +246,13 @@ char * os_readfile(const char *name, size_t *len); */ int os_file_exists(const char *fname); +/** + * os_fdatasync - Sync a file's (for a given stream) state with storage device + * @stream: the stream to be flushed + * Returns: 0 if the operation succeeded or -1 on failure + */ +int os_fdatasync(FILE *stream); + /** * os_zalloc - Allocate and zero memory * @size: Number of bytes to allocate diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c index 77733ad91..ed6eb3c6b 100644 --- a/src/utils/os_internal.c +++ b/src/utils/os_internal.c @@ -243,6 +243,12 @@ char * os_readfile(const char *name, size_t *len) } +int os_fdatasync(FILE *stream) +{ + return 0; +} + + void * os_zalloc(size_t size) { void *n = os_malloc(size); diff --git a/src/utils/os_none.c b/src/utils/os_none.c index 83fe02516..0c3214d32 100644 --- a/src/utils/os_none.c +++ b/src/utils/os_none.c @@ -102,6 +102,12 @@ char * os_readfile(const char *name, size_t *len) } +int os_fdatasync(FILE *stream) +{ + return 0; +} + + void * os_zalloc(size_t size) { return NULL; diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 089b880bd..4754dd7a1 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -418,6 +418,14 @@ int os_file_exists(const char *fname) } +int os_fdatasync(FILE *stream) +{ + if (!fflush(stream)) + return fdatasync(fileno(stream)); + return -1; +} + + #ifndef WPA_TRACE void * os_zalloc(size_t size) { diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c index 296ea13f1..dea27b9f2 100644 --- a/src/utils/os_win32.c +++ b/src/utils/os_win32.c @@ -216,6 +216,24 @@ char * os_readfile(const char *name, size_t *len) } +int os_fdatasync(FILE *stream) +{ + HANDLE h; + + if (stream == NULL) + return -1; + + h = (HANDLE) _get_osfhandle(_fileno(stream)); + if (h == INVALID_HANDLE_VALUE) + return -1; + + if (!FlushFileBuffers(h)) + return -1; + + return 0; +} + + void * os_zalloc(size_t size) { return calloc(1, size); diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 2af187dd4..fb438ea43 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1361,6 +1361,8 @@ int wpa_config_write(const char *name, struct wpa_config *config) } #endif /* CONFIG_NO_CONFIG_BLOBS */ + os_fdatasync(f); + fclose(f); if (tmp_name) {