127 lines
3.4 KiB
Diff
127 lines
3.4 KiB
Diff
From 73b65e94f3531179de45c6f3c836a610e3d0a846 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Stenberg <daniel@haxx.se>
|
|
Date: Thu, 23 Nov 2023 08:23:17 +0100
|
|
Subject: [PATCH] fopen: create short(er) temporary file name
|
|
|
|
Only using random letters in the name plus a ".tmp" extension. Not by
|
|
appending characters to the final file name.
|
|
|
|
Reported-by: Maksymilian Arciemowicz
|
|
|
|
Closes #12388
|
|
---
|
|
lib/fopen.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-----
|
|
1 file changed, 60 insertions(+), 5 deletions(-)
|
|
|
|
Index: curl-8.0.1/lib/fopen.c
|
|
===================================================================
|
|
--- curl-8.0.1.orig/lib/fopen.c
|
|
+++ curl-8.0.1/lib/fopen.c
|
|
@@ -40,6 +40,51 @@
|
|
#include "memdebug.h"
|
|
|
|
/*
|
|
+ The dirslash() function breaks a null-terminated pathname string into
|
|
+ directory and filename components then returns the directory component up
|
|
+ to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
|
|
+ this instead returns a "" string.
|
|
+
|
|
+ This function returns a pointer to malloc'ed memory.
|
|
+
|
|
+ The input path to this function is expected to have a file name part.
|
|
+*/
|
|
+
|
|
+#ifdef _WIN32
|
|
+#define PATHSEP "\\"
|
|
+#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
|
|
+#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
|
|
+#define PATHSEP "\\"
|
|
+#define IS_SEP(x) ((x) == '\\')
|
|
+#else
|
|
+#define PATHSEP "/"
|
|
+#define IS_SEP(x) ((x) == '/')
|
|
+#endif
|
|
+
|
|
+static char *dirslash(const char *path)
|
|
+{
|
|
+ size_t n;
|
|
+ struct dynbuf out;
|
|
+ DEBUGASSERT(path);
|
|
+ Curl_dyn_init(&out, CURL_MAX_INPUT_LENGTH);
|
|
+ n = strlen(path);
|
|
+ if(n) {
|
|
+ /* find the rightmost path separator, if any */
|
|
+ while(n && !IS_SEP(path[n-1]))
|
|
+ --n;
|
|
+ /* skip over all the path separators, if any */
|
|
+ while(n && IS_SEP(path[n-1]))
|
|
+ --n;
|
|
+ }
|
|
+ if(Curl_dyn_addn(&out, path, n))
|
|
+ return NULL;
|
|
+ /* if there was a directory, append a single trailing slash */
|
|
+ if(n && Curl_dyn_addn(&out, PATHSEP, 1))
|
|
+ return NULL;
|
|
+ return Curl_dyn_ptr(&out);
|
|
+}
|
|
+
|
|
+/*
|
|
* Curl_fopen() opens a file for writing with a temp name, to be renamed
|
|
* to the final name when completed. If there is an existing file using this
|
|
* name at the time of the open, this function will clone the mode from that
|
|
@@ -50,25 +95,34 @@ CURLcode Curl_fopen(struct Curl_easy *da
|
|
FILE **fh, char **tempname)
|
|
{
|
|
CURLcode result = CURLE_WRITE_ERROR;
|
|
- unsigned char randsuffix[9];
|
|
+ unsigned char randbuf[41];
|
|
char *tempstore = NULL;
|
|
struct_stat sb;
|
|
int fd = -1;
|
|
+ char *dir;
|
|
*tempname = NULL;
|
|
|
|
+ dir = dirslash(filename);
|
|
+ if(!dir)
|
|
+ goto fail;
|
|
+
|
|
*fh = fopen(filename, FOPEN_WRITETEXT);
|
|
if(!*fh)
|
|
goto fail;
|
|
- if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode))
|
|
+ if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
|
|
+ free(dir);
|
|
return CURLE_OK;
|
|
+ }
|
|
fclose(*fh);
|
|
*fh = NULL;
|
|
|
|
- result = Curl_rand_hex(data, randsuffix, sizeof(randsuffix));
|
|
+ result = Curl_rand_hex(data, randbuf, sizeof(randbuf));
|
|
if(result)
|
|
goto fail;
|
|
|
|
- tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
|
|
+ /* The temp file name should not end up too long for the target file
|
|
+ system */
|
|
+ tempstore = aprintf("%s%s.tmp", dir, randbuf);
|
|
if(!tempstore) {
|
|
result = CURLE_OUT_OF_MEMORY;
|
|
goto fail;
|
|
@@ -95,6 +149,7 @@ CURLcode Curl_fopen(struct Curl_easy *da
|
|
if(!*fh)
|
|
goto fail;
|
|
|
|
+ free(dir);
|
|
*tempname = tempstore;
|
|
return CURLE_OK;
|
|
|
|
@@ -105,7 +160,7 @@ fail:
|
|
}
|
|
|
|
free(tempstore);
|
|
-
|
|
+ free(dir);
|
|
return result;
|
|
}
|
|
|