windows: fix CreateFile() calls to support long filenames

It makes them work in Schannel's CA bundle loader, and curl tool's
set/get file timestamp operations (e.g. in `-R`/`--remote-time`). Also
to match file open operations, that already support long filenames.

E.g. when using `--remote-time`, fixing:
```
Warning: Failed to set filetime 1741363917 on outfile: CreateFile failed:
Warning: GetLastError 0x00000003
```

The special long filename logic is necessary to support Windows releases
prior to Windows 10 v1607. With the latter, it's possible to opt-in to
this behavior via a manifest setting. Note that Windows itself also needs
to opt-in to support this. Finally note that curl itself needs passing
`--globoff` to let long filenames through, pending #20044 and #20046.

Refs:
https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-createfilea
https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation

Ref: #8361
Inspired by: #19286
Inspired-by: Mathesh V
Closes #19286
Closes #20040
This commit is contained in:
Viktor Szakats 2025-12-19 23:26:10 +01:00
parent a468e605eb
commit 969351bb1e
No known key found for this signature in database
GPG key ID: B5ABD165E2AEF201
6 changed files with 75 additions and 30 deletions

View file

@ -41,12 +41,9 @@ int getfiletime(const char *filename, curl_off_t *stamp)
access to a 64-bit type we can bypass stat and get the times directly. */
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP)
HANDLE hfile;
TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar(filename);
hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES,
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
NULL, OPEN_EXISTING, 0, NULL);
curlx_free(tchar_filename);
hfile = curlx_CreateFile(filename, FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
if(hfile != INVALID_HANDLE_VALUE) {
FILETIME ft;
if(GetFileTime(hfile, NULL, NULL, &ft)) {
@ -93,7 +90,6 @@ void setfiletime(curl_off_t filetime, const char *filename)
access to a 64-bit type we can bypass utime and set the times directly. */
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP)
HANDLE hfile;
TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar(filename);
/* 910670515199 is the maximum Unix filetime that can be used as a Windows
FILETIME without overflow: 30827-12-31T23:59:59. */
@ -108,10 +104,9 @@ void setfiletime(curl_off_t filetime, const char *filename)
warnf("Capping set filetime to minimum to avoid overflow");
}
hfile = CreateFile(tchar_filename, FILE_WRITE_ATTRIBUTES,
(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
NULL, OPEN_EXISTING, 0, NULL);
curlx_free(tchar_filename);
hfile = curlx_CreateFile(filename, FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
if(hfile != INVALID_HANDLE_VALUE) {
curl_off_t converted = ((curl_off_t)filetime * 10000000) +
116444736000000000;