diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rwxr-xr-x | configure.ac | 1 | ||||
-rw-r--r-- | lib/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/altsvc.c | 38 | ||||
-rw-r--r-- | lib/altsvc.h | 7 | ||||
-rw-r--r-- | lib/cookie.c | 39 | ||||
-rw-r--r-- | lib/curl_config.h.cmake | 3 | ||||
-rw-r--r-- | lib/hsts.c | 34 | ||||
-rw-r--r-- | lib/openlock.c | 108 | ||||
-rw-r--r-- | lib/openlock.h (renamed from lib/rename.h) | 17 | ||||
-rw-r--r-- | lib/rename.c | 71 | ||||
-rw-r--r-- | lib/url.c | 2 | ||||
-rw-r--r-- | tests/unit/unit1654.c | 2 |
13 files changed, 162 insertions, 165 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ffb72faf..65f9a21aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1045,6 +1045,7 @@ check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) check_symbol_exists(getpeername "${CURL_INCLUDES}" HAVE_GETPEERNAME) check_symbol_exists(getsockname "${CURL_INCLUDES}" HAVE_GETSOCKNAME) check_symbol_exists(if_nametoindex "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX) +check_symbol_exists(lockf "${CURL_INCLUDES}" HAVE_LOCKF) check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE) diff --git a/configure.ac b/configure.ac index 8b3ff904c..2321052ad 100755 --- a/configure.ac +++ b/configure.ac @@ -3351,6 +3351,7 @@ AC_CHECK_FUNCS([fnmatch \ getrlimit \ gettimeofday \ if_nametoindex \ + lockf \ mach_absolute_time \ pipe \ setlocale \ diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 3e9ddec12..fbd1426f6 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -173,13 +173,13 @@ LIB_CFILES = \ non-ascii.c \ nonblock.c \ openldap.c \ + openlock.c \ parsedate.c \ pingpong.c \ pop3.c \ progress.c \ psl.c \ rand.c \ - rename.c \ rtsp.c \ select.c \ sendf.c \ @@ -293,6 +293,7 @@ LIB_HFILES = \ netrc.h \ non-ascii.h \ nonblock.h \ + openlock.h \ parsedate.h \ pingpong.h \ pop3.h \ @@ -300,7 +301,6 @@ LIB_HFILES = \ psl.h \ quic.h \ rand.h \ - rename.h \ rtsp.h \ select.h \ sendf.h \ diff --git a/lib/altsvc.c b/lib/altsvc.c index 4ab77fdfc..610969a97 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,8 +34,7 @@ #include "parsedate.h" #include "sendf.h" #include "warnless.h" -#include "rand.h" -#include "rename.h" +#include "openlock.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -322,15 +321,12 @@ void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp) /* * Curl_altsvc_save() writes the altsvc cache to a file. */ -CURLcode Curl_altsvc_save(struct Curl_easy *data, - struct altsvcinfo *altsvc, const char *file) +CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file) { struct Curl_llist_element *e; struct Curl_llist_element *n; + struct openlock o; CURLcode result = CURLE_OK; - FILE *out; - char *tempstore; - unsigned char randsuffix[9]; if(!altsvc) /* no cache activated */ @@ -344,35 +340,23 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, /* marked as read-only, no file or zero length file name */ return CURLE_OK; - if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) - return CURLE_FAILED_INIT; - - tempstore = aprintf("%s.%s.tmp", file, randsuffix); - if(!tempstore) - return CURLE_OUT_OF_MEMORY; - - out = fopen(tempstore, FOPEN_WRITETEXT); - if(!out) - result = CURLE_WRITE_ERROR; + result = Curl_openlock(file, &o); + if(result) + goto error; else { fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", - out); + o.out); for(e = altsvc->list.head; e; e = n) { struct altsvc *as = e->ptr; n = e->next; - result = altsvc_out(as, out); + result = altsvc_out(as, o.out); if(result) break; } - fclose(out); - if(!result && Curl_rename(tempstore, file)) - result = CURLE_WRITE_ERROR; - - if(result) - unlink(tempstore); } - free(tempstore); + error: + Curl_openunlock(&o); return result; } diff --git a/lib/altsvc.h b/lib/altsvc.h index 2ab89e705..c17610167 100644 --- a/lib/altsvc.h +++ b/lib/altsvc.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -58,8 +58,7 @@ struct altsvcinfo { const char *Curl_alpnid2str(enum alpnid id); struct altsvcinfo *Curl_altsvc_init(void); CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file); -CURLcode Curl_altsvc_save(struct Curl_easy *data, - struct altsvcinfo *asi, const char *file); +CURLcode Curl_altsvc_save(struct altsvcinfo *asi, const char *file); CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl); void Curl_altsvc_cleanup(struct altsvcinfo **altsvc); CURLcode Curl_altsvc_parse(struct Curl_easy *data, @@ -73,7 +72,7 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi, const int versions); /* CURLALTSVC_H* bits */ #else /* disabled */ -#define Curl_altsvc_save(a,b,c) +#define Curl_altsvc_save(a,b) #define Curl_altsvc_cleanup(x) #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */ #endif /* HEADER_CURL_ALTSVC_H */ diff --git a/lib/cookie.c b/lib/cookie.c index 8831b2a0e..2183d5a19 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -83,7 +83,6 @@ Example set of cookies: #include "curl_setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) - #include "urldata.h" #include "cookie.h" #include "psl.h" @@ -97,8 +96,7 @@ Example set of cookies: #include "curl_memrchr.h" #include "inet_pton.h" #include "parsedate.h" -#include "rand.h" -#include "rename.h" +#include "openlock.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -1515,14 +1513,13 @@ static char *get_netscape_format(const struct Cookie *co) * * The function returns non-zero on write failure. */ -static int cookie_output(struct Curl_easy *data, - struct CookieInfo *c, const char *filename) +static int cookie_output(struct CookieInfo *c, const char *filename) { struct Cookie *co; FILE *out = NULL; bool use_stdout = FALSE; - char *tempstore = NULL; bool error = false; + struct openlock o; if(!c) /* no cookie engine alive */ @@ -1537,18 +1534,10 @@ static int cookie_output(struct Curl_easy *data, use_stdout = TRUE; } else { - unsigned char randsuffix[9]; - - if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) - return 2; - - tempstore = aprintf("%s.%s.tmp", filename, randsuffix); - if(!tempstore) - return 1; - - out = fopen(tempstore, FOPEN_WRITETEXT); - if(!out) + CURLcode result = Curl_openlock(filename, &o); + if(result) goto error; + out = o.out; } fputs("# Netscape HTTP Cookie File\n" @@ -1591,22 +1580,12 @@ static int cookie_output(struct Curl_easy *data, free(array); } - if(!use_stdout) { - fclose(out); - out = NULL; - if(Curl_rename(tempstore, filename)) { - unlink(tempstore); - goto error; - } - } - goto cleanup; error: error = true; cleanup: - if(out && !use_stdout) - fclose(out); - free(tempstore); + if(!use_stdout) + Curl_openunlock(&o); return error ? 1 : 0; } @@ -1665,7 +1644,7 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); /* if we have a destination file for all the cookies to get dumped to */ - if(cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR])) + if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR])) infof(data, "WARNING: failed to save cookies in %s\n", data->set.str[STRING_COOKIEJAR]); } diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 1f298871e..c32d2f22d 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -268,6 +268,9 @@ /* Define to 1 if you have the `if_nametoindex' function. */ #cmakedefine HAVE_IF_NAMETOINDEX 1 +/* Define to 1 if you have the `lockf' function. */ +#cmakedefine HAVE_LOCKF 1 + /* Define to 1 if you have the `getpwuid' function. */ #cmakedefine HAVE_GETPWUID 1 diff --git a/lib/hsts.c b/lib/hsts.c index ef166f196..5923671e9 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -35,9 +35,7 @@ #include "sendf.h" #include "strtoofft.h" #include "parsedate.h" -#include "rand.h" -#include "rename.h" -#include "strtoofft.h" +#include "openlock.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -319,9 +317,8 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, struct Curl_llist_element *e; struct Curl_llist_element *n; CURLcode result = CURLE_OK; - FILE *out; - char *tempstore; - unsigned char randsuffix[9]; + FILE *out = NULL; + struct openlock o; if(!h) /* no cache activated */ @@ -335,17 +332,9 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, /* marked as read-only, no file or zero length file name */ goto skipsave; - if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) - return CURLE_FAILED_INIT; - - tempstore = aprintf("%s.%s.tmp", file, randsuffix); - if(!tempstore) - return CURLE_OUT_OF_MEMORY; - - out = fopen(tempstore, FOPEN_WRITETEXT); - if(!out) - result = CURLE_WRITE_ERROR; - else { + result = Curl_openlock(file, &o); + if(!result) { + out = o.out; fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", out); @@ -356,14 +345,8 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, if(result) break; } - fclose(out); - if(!result && Curl_rename(tempstore, file)) - result = CURLE_WRITE_ERROR; - - if(result) - unlink(tempstore); } - free(tempstore); + skipsave: if(data->set.hsts_write) { /* if there's a write callback */ @@ -380,6 +363,9 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, i.index++; } } + if(out) + Curl_openunlock(&o); + return result; } diff --git a/lib/openlock.c b/lib/openlock.c new file mode 100644 index 000000000..f913ef82f --- /dev/null +++ b/lib/openlock.c @@ -0,0 +1,108 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <curl/curl.h> +#include "openlock.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_openlock() opens a file for writing text and waits for the adivsory + * lock on it. + */ + +#ifndef O_CLOEXEC +/* this doesn't exist everywhere */ +#define O_CLOEXEC 0 +#endif + +CURLcode Curl_openlock(const char *file, struct openlock *o) +{ + int fd = -1; + FILE *out = NULL; + CURLcode result = CURLE_OK; + + DEBUGASSERT(o); + o->fd = -1; + o->out = NULL; + + fd = open(file, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666); + if(fd == -1) { + result = CURLE_WRITE_ERROR; + goto error; + } + +#ifdef HAVE_LOCKF + /* wait for advisory lock on the whole file */ + if(lockf(fd, F_LOCK, 0)) { + result = CURLE_WRITE_ERROR; + goto error; + } +#endif + + out = fdopen(fd, FOPEN_WRITETEXT); + if(!out) + result = CURLE_WRITE_ERROR; + else { + o->fd = fd; + o->out = out; + return CURLE_OK; + } + error: + if(out) + /* fclose() will close the fd as well after fdopen */ + fclose(out); + else if(fd != -1) + close(fd); + return result; +} + +/* + * Truncate the file at the current position, then unlock and close it. + */ +void Curl_openunlock(struct openlock *o) +{ +#ifdef HAVE_FTRUNCATE + long pos = ftell(o->out); + fflush(o->out); + if(ftruncate(o->fd, (off_t)pos)) + /* ignoring the return code causes warnings ... */ + pos = 0; +#endif +#ifdef HAVE_LOCKF + if(o->fd != -1) { + if(lockf(o->fd, F_ULOCK, 0)) { + o->fd = -1; + } + } +#endif + if(o->out) + fclose(o->out); +} diff --git a/lib/rename.h b/lib/openlock.h index 534f7471c..b287bead2 100644 --- a/lib/rename.h +++ b/lib/openlock.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_RENAME_H -#define HEADER_CURL_RENAME_H +#ifndef HEADER_CURL_OPENLOCK_H +#define HEADER_CURL_OPENLOCK_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,7 +21,14 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "curl_setup.h" -int Curl_rename(const char *oldpath, const char *newpath); +struct openlock { + int fd; + FILE *out; +}; -#endif /* HEADER_CURL_RENAME_H */ +CURLcode Curl_openlock(const char *file, struct openlock *o); +void Curl_openunlock(struct openlock *o); + +#endif /* HEADER_CURL_OPENLOCK_H */ diff --git a/lib/rename.c b/lib/rename.c deleted file mode 100644 index f858d4369..000000000 --- a/lib/rename.c +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "rename.h" - -#include "curl_setup.h" - -#if (!defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_COOKIES)) || \ - !defined(CURL_DISABLE_ALTSVC) - -#include "curl_multibyte.h" -#include "timeval.h" - -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -/* return 0 on success, 1 on error */ -int Curl_rename(const char *oldpath, const char *newpath) -{ -#ifdef WIN32 - /* rename() on Windows doesn't overwrite, so we can't use it here. - MoveFileEx() will overwrite and is usually atomic, however it fails - when there are open handles to the file. */ - const int max_wait_ms = 1000; - struct curltime start = Curl_now(); - TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar((char *)oldpath); - TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar((char *)newpath); - for(;;) { - timediff_t diff; - if(MoveFileEx(tchar_oldpath, tchar_newpath, MOVEFILE_REPLACE_EXISTING)) { - curlx_unicodefree(tchar_oldpath); - curlx_unicodefree(tchar_newpath); - break; - } - diff = Curl_timediff(Curl_now(), start); - if(diff < 0 || diff > max_wait_ms) { - curlx_unicodefree(tchar_oldpath); - curlx_unicodefree(tchar_newpath); - return 1; - } - Sleep(1); - } -#else - if(rename(oldpath, newpath)) - return 1; -#endif - return 0; -} - -#endif @@ -416,7 +416,7 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_dyn_free(&data->state.headerb); Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, TRUE); - Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); + Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]); Curl_altsvc_cleanup(&data->asi); Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); Curl_hsts_cleanup(&data->hsts); diff --git a/tests/unit/unit1654.c b/tests/unit/unit1654.c index acd2cd62f..7ac1d1981 100644 --- a/tests/unit/unit1654.c +++ b/tests/unit/unit1654.c @@ -127,7 +127,7 @@ UNITTEST_START } fail_unless(asi->list.size == 10, "wrong number of entries"); - Curl_altsvc_save(curl, asi, outname); + Curl_altsvc_save(asi, outname); curl_easy_cleanup(curl); curl_global_cleanup(); |