tool_xattr: add support for Windows alternate data stream
No binary (build failed)
—
(log yok)
| @@ -392,6 +392,7 @@ IMAPS | |
| imaps | |
| impacket | |
| implementers | |
| + | INI |
| init | |
| initializer | |
| inlined | |
| @@ -20,6 +20,11 @@ Store metadata in the extended file attributes. | |
| When saving output to a file, tell curl to store file metadata in extended | |
| file attributes. Currently, `curl` is stored in the `creator` attribute, | |
| - | the URL is stored in the `xdg.origin.url` attribute and, for HTTP, the content |
| - | type is stored in the `mime_type` attribute. If the file system does not |
| - | support extended attributes, a warning is issued. |
| + | the URL is stored in the `xdg.origin.url` attribute, for HTTP, the content |
| + | type is stored in the `mime_type` attribute, and if set, the referrer URL in |
| + | `user.xdg.referrer.url`. If the file system does not support extended |
| + | attributes, a warning is issued. |
| + | |
| + | Since curl 8.22.0 this option is also supported on Windows, where it creates |
| + | an Alternate Data Stream named `Zone.Identifier`. It contains an INI formatted |
| + | `ZoneTransfer` section, with values: `HostUrl`, `ReferrerUrl` (if set). |
| @@ -650,7 +650,7 @@ static CURLcode post_output_handling(struct per_transfer *per, | |
| /* Set file extended attributes */ | |
| if(!result && config->xattr && outs->fopened && outs->stream) { | |
| - | rc = fwrite_xattr(curl, per->url, fileno(outs->stream)); |
| + | rc = fwrite_xattr(curl, per->url, fileno(outs->stream), outs->filename); |
| if(rc) { | |
| char errbuf[STRERROR_LEN]; | |
| warnf("Error setting extended attributes on '%s': %s", outs->filename, | |
| @@ -27,19 +27,6 @@ | |
| #ifdef USE_XATTR | |
| - | /* mapping table of curl metadata to extended attribute names */ |
| - | static const struct xattr_mapping { |
| - | const char *attr; /* name of the xattr */ |
| - | CURLINFO info; |
| - | } mappings[] = { |
| - | /* mappings proposed by |
| - | * https://freedesktop.org/wiki/CommonExtendedAttributes/ |
| - | */ |
| - | { "user.xdg.referrer.url", CURLINFO_REFERER }, |
| - | { "user.mime_type", CURLINFO_CONTENT_TYPE }, |
| - | { NULL, CURLINFO_NONE } /* last element, abort here */ |
| - | }; |
| - | |
| /* returns a new URL that needs to be freed */ | |
| /* @unittest: 1621 */ | |
| UNITTEST char *stripcredentials(const char *url) | |
| @@ -74,6 +61,20 @@ error: | |
| return NULL; | |
| } | |
| + | #ifndef _WIN32 |
| + | /* mapping table of curl metadata to extended attribute names */ |
| + | static const struct xattr_mapping { |
| + | const char *attr; /* name of the xattr */ |
| + | CURLINFO info; |
| + | } mappings[] = { |
| + | /* mappings proposed by |
| + | * https://freedesktop.org/wiki/CommonExtendedAttributes/ |
| + | */ |
| + | { "user.xdg.referrer.url", CURLINFO_REFERER }, |
| + | { "user.mime_type", CURLINFO_CONTENT_TYPE }, |
| + | { NULL, CURLINFO_NONE } /* last element, abort here */ |
| + | }; |
| + | |
| static int xattr(int fd, | |
| const char *attr, /* name of the xattr */ | |
| const char *value) | |
| @@ -102,13 +103,70 @@ static int xattr(int fd, | |
| } | |
| return err; | |
| } | |
| + | #else |
| + | static int win32_file_stream(CURL *curl, FILE *fs, const char *url) |
| + | { |
| + | int err = 1; |
| + | char *value = NULL; |
| + | char *nurl = stripcredentials(url); |
| + | CURLcode result = curl_easy_getinfo(curl, CURLINFO_REFERER, &value); |
| + | |
| + | if(nurl && !result) { |
| + | err = 0; |
| + | err |= (fputs("[ZoneTransfer]\n", fs) == EOF); |
| + | if(value) { |
| + | err |= (fputs("ReferrerUrl=", fs) == EOF); |
| + | err |= (fputs(value, fs) == EOF); |
| + | err |= (fputs("\n", fs) == EOF); |
| + | } |
| + | err |= (fputs("HostUrl=", fs) == EOF); |
| + | err |= (fputs(nurl, fs) == EOF); |
| + | err |= (fputs("\n", fs) == EOF); |
| + | } |
| + | curl_free(nurl); |
| + | return err; |
| + | } |
| + | #endif /* !_WIN32 */ |
| + | |
| /* store metadata from the curl request alongside the downloaded | |
| * file using extended attributes | |
| */ | |
| - | int fwrite_xattr(CURL *curl, const char *url, int fd) |
| + | int fwrite_xattr(CURL *curl, const char *url, int fd, const char *filename) |
| { | |
| + | int err; |
| + | #ifdef _WIN32 |
| + | char *fn_abs, *fn_stream; |
| + | FILE *fs; |
| + | (void)fd; |
| + | |
| + | /* convert to absolute path to prevent Windows interpreting a 'X:<stream>' |
| + | filename as 'drive-letter:<filename>'. */ |
| + | fn_abs = _fullpath(NULL, filename, 0); |
| + | if(!fn_abs) |
| + | return 1; |
| + | |
| + | fn_stream = curl_maprintf("%s:%s", fn_abs, "Zone.Identifier"); |
| + | /* !checksrc! disable BANNEDFUNC 1 */ |
| + | free(fn_abs); /* allocated by CRT, use system free() */ |
| + | if(!fn_stream) |
| + | return 1; |
| + | |
| + | fs = curlx_fopen(fn_stream, FOPEN_WRITETEXT); |
| + | curl_free(fn_stream); |
| + | if(!fs) |
| + | return 1; |
| + | |
| + | #ifdef DEBUGBUILD |
| + | if(getenv("CURL_FAKE_XATTR")) |
| + | win32_file_stream(curl, stdout, url); |
| + | #endif |
| + | err = win32_file_stream(curl, fs, url); |
| + | curlx_fclose(fs); |
| + | #else |
| int i = 0; | |
| - | int err = xattr(fd, "user.creator", "curl"); |
| + | (void)filename; |
| + | |
| + | err = xattr(fd, "user.creator", "curl"); |
| /* loop through all xattr-curlinfo pairs and abort on a set error */ | |
| while(!err && mappings[i].attr) { | |
| @@ -125,6 +183,7 @@ int fwrite_xattr(CURL *curl, const char *url, int fd) | |
| err = xattr(fd, "user.xdg.origin.url", nurl); | |
| curl_free(nurl); | |
| } | |
| + | #endif |
| return err; | |
| } | |
| #endif | |
| @@ -33,17 +33,19 @@ | |
| # include <sys/types.h> | |
| # include <sys/extattr.h> | |
| # define USE_XATTR | |
| + | #elif defined(_WIN32) |
| + | # define USE_XATTR |
| #endif | |
| #ifdef USE_XATTR | |
| - | int fwrite_xattr(CURL *curl, const char *url, int fd); |
| + | int fwrite_xattr(CURL *curl, const char *url, int fd, const char *filename); |
| #ifdef UNITTESTS | |
| UNITTEST char *stripcredentials(const char *url); | |
| #endif | |
| #else | |
| - | #define fwrite_xattr(a, b, c) 0 |
| + | #define fwrite_xattr(a, b, c, d) 0 |
| #endif | |
| #endif /* HEADER_CURL_TOOL_XATTR_H */ | |
| @@ -76,9 +76,14 @@ Accept: */* | |
| </protocol> | |
| <stdout mode="text"> | |
| + | %if win32 |
| + | [ZoneTransfer] |
| + | HostUrl=http://%HOSTIP:%HTTPPORT/%TESTNUMBER |
| + | %else |
| user.creator => curl | |
| user.mime_type => text/html | |
| user.xdg.origin.url => http://%HOSTIP:%HTTPPORT/%TESTNUMBER | |
| + | %endif |
| </stdout> | |
| </verify> | |
| </testcase> | |
| @@ -53,9 +53,14 @@ Accept: */* | |
| </protocol> | |
| <stdout mode="text"> | |
| + | %if win32 |
| + | [ZoneTransfer] |
| + | HostUrl=http://%HOSTIP:%HTTPPORT/%TESTNUMBER |
| + | %else |
| user.creator => curl | |
| user.mime_type => fake/data | |
| user.xdg.origin.url => http://%HOSTIP:%HTTPPORT/%TESTNUMBER | |
| + | %endif |
| </stdout> | |
| </verify> | |
| </testcase> | |
| @@ -39,7 +39,7 @@ CURL_FAKE_XATTR=1 | |
| basic --xattr with (uppercase) -O | |
| </name> | |
| <command> | |
| - | --xattr -O --output-dir %LOGDIR http://%HOSTIP:%HTTPPORT/%TESTNUMBER |
| + | --xattr -O --output-dir %LOGDIR http://%HOSTIP:%HTTPPORT/%TESTNUMBER --referer https://referrer.invalid/ |
| </command> | |
| </client> | |
| @@ -50,12 +50,20 @@ GET /%TESTNUMBER HTTP/1.1 | |
| Host: %HOSTIP:%HTTPPORT | |
| User-Agent: curl/%VERSION | |
| Accept: */* | |
| + | Referer: https://referrer.invalid/ |
| </protocol> | |
| <stdout mode="text"> | |
| + | %if win32 |
| + | [ZoneTransfer] |
| + | ReferrerUrl=https://referrer.invalid/ |
| + | HostUrl=http://%HOSTIP:%HTTPPORT/%TESTNUMBER |
| + | %else |
| user.creator => curl | |
| + | user.xdg.referrer.url => https://referrer.invalid/ |
| user.mime_type => fake/data | |
| user.xdg.origin.url => http://%HOSTIP:%HTTPPORT/%TESTNUMBER | |
| + | %endif |
| </stdout> | |
| </verify> | |
| </testcase> | |