tool_cb_wrt: inject the no-clobber number before the extension
No binary (build failed)
—
(log yok)
| @@ -21,6 +21,11 @@ that already exist. Instead, a dot and a number gets appended to the name of | |
| the file that would be created, up to filename.9999 after which it does not | |
| create any file. | |
| + | Starting in curl 8.23.0, if the target filename uses an extension, curl |
| + | instead creates the new filename by inserting `-[num]` before the extension. |
| + | Downloading to `image.jpg` with --no-clobber, curl first tries to save it as |
| + | `image-1.jpg` then `image-2.jpg` etc. |
| + | |
| Note that this is the negated option name documented. You can thus use | |
| --clobber to enforce the clobbering, even if --remote-header-name is | |
| specified. | |
| @@ -36,6 +36,40 @@ | |
| #define MAX_CLOBBER_ATTEMPTS 9999 | |
| + | /* 'fname' contains [path + ] file name */ |
| + | static bool clobber_name(struct dynbuf *fbuf, const char *fname, |
| + | int next_num) |
| + | { |
| + | /* skip the directory, if present */ |
| + | const char *slash = strrchr(fname, '/'); |
| + | const char *base = fname; |
| + | const char *dot; |
| + | #ifdef _WIN32 |
| + | const char *bslash = strrchr(fname, '\\'); |
| + | /* use the one furthest away */ |
| + | if(bslash && (!slash || (bslash > slash))) |
| + | slash = bslash; |
| + | #endif |
| + | if(slash) |
| + | base = slash + 1; |
| + | |
| + | dot = strrchr(base, '.'); |
| + | curlx_dyn_reset(fbuf); |
| + | if(dot && (dot != base) && dot[1]) { |
| + | /* there is an extension after the dot and the dot is not the first file |
| + | name character */ |
| + | int prefix = (int)(dot - fname); |
| + | if(curlx_dyn_addf(fbuf, "%.*s-%d.%s", prefix, fname, next_num, dot + 1)) |
| + | return FALSE; |
| + | } |
| + | else { |
| + | /* without any extension */ |
| + | if(curlx_dyn_addf(fbuf, "%s.%d", fname, next_num)) |
| + | return FALSE; |
| + | } |
| + | return TRUE; |
| + | } |
| + | |
| /* create/open a local file for writing, return TRUE on success */ | |
| bool tool_create_output_file(struct OutStruct *outs, | |
| struct OperationConfig *config) | |
| @@ -82,8 +116,7 @@ bool tool_create_output_file(struct OutStruct *outs, | |
| (errno == EEXIST || errno == EISDIR) && | |
| /* and we have not reached the retry limit */ | |
| (next_num < max_num)) { | |
| - | curlx_dyn_reset(&fbuffer); |
| - | if(curlx_dyn_addf(&fbuffer, "%s.%d", fname, next_num)) |
| + | if(!clobber_name(&fbuffer, fname, next_num)) |
| return FALSE; | |
| next_num++; | |
| do { | |
| @@ -2096,7 +2096,7 @@ TESTCASES = \ | |
| \ | |
| test4000 \ | |
| test4001 \ | |
| - | \ |
| + | test4644 \ |
| test5000 \ | |
| test5001 \ | |
| test5002 \ | |
| @@ -0,0 +1,56 @@ | |
| + | <?xml version="1.0" encoding="US-ASCII"?> |
| + | <testcase> |
| + | <info> |
| + | <keywords> |
| + | --no-clobber |
| + | </keywords> |
| + | </info> |
| + | |
| + | <reply> |
| + | <data nocheck="yes"> |
| + | HTTP/1.1 200 OK swsclose |
| + | Content-Length: 12 |
| + | Connection: close |
| + | Content-Type: text/html |
| + | |
| + | new content |
| + | </data> |
| + | </reply> |
| + | |
| + | <client> |
| + | <file name="%LOGDIR/save.txt"> |
| + | exists before command runs |
| + | </file> |
| + | <file1 name="%LOGDIR/save-1.txt"> |
| + | exists before command runs |
| + | </file1> |
| + | <server> |
| + | http |
| + | </server> |
| + | <name> |
| + | --no-clobber with extension and an added number |
| + | </name> |
| + | <command option="no-output,no-include"> |
| + | http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/save.txt --no-clobber |
| + | </command> |
| + | </client> |
| + | |
| + | # Verify data after the test has been "shot". |
| + | <verify> |
| + | <protocol crlf="headers"> |
| + | GET /%TESTNUMBER HTTP/1.1 |
| + | Host: %HOSTIP:%HTTPPORT |
| + | User-Agent: curl/%VERSION |
| + | Accept: */* |
| + | |
| + | </protocol> |
| + | |
| + | # this file should be untouched |
| + | <file name="%LOGDIR/save.txt"> |
| + | exists before command runs |
| + | </file> |
| + | <file2 name="%LOGDIR/save-2.txt"> |
| + | new content |
| + | </file2> |
| + | </verify> |
| + | </testcase> |