summaryrefslogtreecommitdiff
path: root/lib/altsvc.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2020-02-17 23:01:48 +0100
committerDaniel Stenberg <daniel@haxx.se>2020-02-18 07:49:21 +0100
commit14916a82e23c22e1f3d3ebbd90421eb747480e99 (patch)
tree12adec5225ec862e7f330da1539e0d37e3aba105 /lib/altsvc.c
parent330f133224af18c65b9325d9b6502e07b4f09f6b (diff)
downloadcurl-14916a82e23c22e1f3d3ebbd90421eb747480e99.tar.gz
altsvc: make saving the cache an atomic operation
... by writing the file to temp name then rename to the final when done. Assisted-by: Jay Satiro Fixes #4936 Closes #4942
Diffstat (limited to 'lib/altsvc.c')
-rw-r--r--lib/altsvc.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/lib/altsvc.c b/lib/altsvc.c
index c05562985..8066302ae 100644
--- a/lib/altsvc.c
+++ b/lib/altsvc.c
@@ -34,6 +34,8 @@
#include "parsedate.h"
#include "sendf.h"
#include "warnless.h"
+#include "rand.h"
+#include "rename.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -317,12 +319,15 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
/*
* Curl_altsvc_save() writes the altsvc cache to a file.
*/
-CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file)
+CURLcode Curl_altsvc_save(struct Curl_easy *data,
+ struct altsvcinfo *altsvc, const char *file)
{
struct curl_llist_element *e;
struct curl_llist_element *n;
CURLcode result = CURLE_OK;
FILE *out;
+ char *tempstore;
+ unsigned char randsuffix[9];
if(!altsvc)
/* no cache activated */
@@ -335,20 +340,36 @@ CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file)
if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
/* marked as read-only, no file or zero length file name */
return CURLE_OK;
- out = fopen(file, FOPEN_WRITETEXT);
+
+ 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)
- return CURLE_WRITE_ERROR;
- fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n"
- "# This file was generated by libcurl! Edit at your own risk.\n",
- out);
- for(e = altsvc->list.head; e; e = n) {
- struct altsvc *as = e->ptr;
- n = e->next;
- result = altsvc_out(as, out);
+ result = CURLE_WRITE_ERROR;
+ else {
+ fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n"
+ "# This file was generated by libcurl! Edit at your own risk.\n",
+ out);
+ for(e = altsvc->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
+ result = altsvc_out(as, out);
+ if(result)
+ break;
+ }
+ fclose(out);
+ if(!result && Curl_rename(tempstore, file))
+ result = CURLE_WRITE_ERROR;
+
if(result)
- break;
+ unlink(tempstore);
}
- fclose(out);
+ free(tempstore);
return result;
}