From a9671a77476b0dac171cf5ba1f9882fd66a4e038 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Wolfgang=20St=C3=B6ggl?= Date: Fri, 18 Jan 2019 18:05:47 +0100 Subject: [PATCH] Fix: Cannot rename temporary file to final file - Fixes the following failing tests under Windows: modify1, modify2, modify3, modify4, modify5 - Use CreateFileA() with FILE_SHARE_DELETE in rrd_open.c, so that the outfilename can later be replaced by tmpfilename using write_rrd() in rrd_create.c --- src/rrd_create.c | 23 ++++++++++++++++++++--- src/rrd_open.c | 16 ++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/rrd_create.c b/src/rrd_create.c index 464073b7..32e9ce2f 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -1482,13 +1482,30 @@ int write_rrd( } #ifdef WIN32 -/* in windows, renaming to an existing file is verboten */ - unlink(outfilename); -#endif +/* In Windows, renaming to an existing file is not allowed. Even, if the file + * is deleted before, using _unlink() here. Furthermore the FILE_SHARE_DELETE + * flag is required, which is used in CreateFileA in rrd_open.c + * Check first, if the file exists. Use ReplaceFileA if the file exists. + * Otherwise rename as usual */ + if (_access_s(outfilename, 0) == 0) { + if (ReplaceFileA(outfilename, tmpfilename, NULL, 0, 0, 0) == + 0) { + rrd_set_error("Cannot replace %s!", outfilename); + goto done; + } + } else { + if (rename(tmpfilename, outfilename) != 0) { + rrd_set_error + ("Cannot rename temporary file to final file!"); + goto done; + } + } +#else if (rename(tmpfilename, outfilename) != 0) { rrd_set_error("Cannot rename temporary file to final file!"); goto done; } +#endif // after the rename: forget the file again, just to be sure... if (rrdc_is_any_connected()) { diff --git a/src/rrd_open.c b/src/rrd_open.c index 03377710..d02acfe2 100644 --- a/src/rrd_open.c +++ b/src/rrd_open.c @@ -270,10 +270,26 @@ rrd_file_t *rrd_open( flags |= O_BINARY; #endif +#if defined(_WIN32) + /* In Windows we need FILE_SHARE_DELETE, so that the file can be + * renamed/replaced later on in rrd_create.c + * This is only possible using CreateFileA() first and not using open() alone */ + HANDLE handle; + + handle = + CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if ((rrd_simple_file->fd = _open_osfhandle((intptr_t) handle, flags)) < 0) { + rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno)); + goto out_free; + } +#else if ((rrd_simple_file->fd = open(file_name, flags, 0666)) < 0) { rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno)); goto out_free; } +#endif #ifdef HAVE_MMAP #ifdef HAVE_BROKEN_MS_ASYNC -- 2.47.2