From: Wolfgang Stöggl Date: Fri, 18 Jan 2019 17:05:47 +0000 (+0100) Subject: Fix: Cannot rename temporary file to final file X-Git-Tag: v1.7.1~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a9671a7;p=thirdparty%2Frrdtool-1.x.git 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 --- 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