#include "../curl_setup.h"
#include "fopen.h"
int curlx_fseek(void *stream, curl_off_t offset, int whence)
{
#if defined(_WIN32) && defined(USE_WIN32_LARGE_FILES)
return _fseeki64(stream, (__int64)offset, whence);
#elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
return fseeko(stream, (off_t)offset, whence);
#else
if(offset > LONG_MAX)
return -1;
return fseek(stream, (long)offset, whence);
#endif
}
#if defined(_WIN32) && !defined(UNDER_CE)
#include "multibyte.h"
#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
(_WIN32_WINNT < _WIN32_WINNT_WIN10)
WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
#endif
static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
{
size_t needed, count;
const wchar_t *in_w;
wchar_t *fbuf = NULL;
const size_t max_path_len = 32767;
#ifndef _UNICODE
wchar_t *ibuf = NULL;
char *obuf = NULL;
#endif
*out = NULL;
if(!_tcsncmp(in, _T("\\\\?\\"), 4))
goto cleanup;
#ifndef _UNICODE
needed = mbstowcs(NULL, in, 0);
if(needed == (size_t)-1 || needed >= max_path_len)
goto cleanup;
++needed;
ibuf = (malloc)(needed * sizeof(wchar_t));
if(!ibuf)
goto cleanup;
count = mbstowcs(ibuf, in, needed);
if(count == (size_t)-1 || count >= needed)
goto cleanup;
in_w = ibuf;
#else
in_w = in;
#endif
needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL);
if(!needed || needed > max_path_len)
goto cleanup;
if(needed <= MAX_PATH)
goto cleanup;
fbuf = (malloc)(needed * sizeof(wchar_t));
if(!fbuf)
goto cleanup;
count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
if(!count || count >= needed)
goto cleanup;
if(!wcsncmp(fbuf, L"\\\\?\\", 4))
;
else if(!wcsncmp(fbuf, L"\\\\.\\", 4))
fbuf[2] = '?';
else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) {
goto cleanup;
}
else {
wchar_t *temp;
if(!wcsncmp(fbuf, L"\\\\", 2)) {
needed = 8 + (count - 2) + 1;
if(needed > max_path_len)
goto cleanup;
temp = (malloc)(needed * sizeof(wchar_t));
if(!temp)
goto cleanup;
wcsncpy(temp, L"\\\\?\\UNC\\", 8);
wcscpy(temp + 8, fbuf + 2);
}
else {
needed = 4 + count + 1;
if(needed > max_path_len)
goto cleanup;
temp = (malloc)(needed * sizeof(wchar_t));
if(!temp)
goto cleanup;
wcsncpy(temp, L"\\\\?\\", 4);
wcscpy(temp + 4, fbuf);
}
(free)(fbuf);
fbuf = temp;
}
#ifndef _UNICODE
needed = wcstombs(NULL, fbuf, 0);
if(needed == (size_t)-1 || needed >= max_path_len)
goto cleanup;
++needed;
obuf = (malloc)(needed);
if(!obuf)
goto cleanup;
count = wcstombs(obuf, fbuf, needed);
if(count == (size_t)-1 || count >= needed)
goto cleanup;
*out = obuf;
obuf = NULL;
#else
*out = fbuf;
fbuf = NULL;
#endif
cleanup:
(free)(fbuf);
#ifndef _UNICODE
(free)(ibuf);
(free)(obuf);
#endif
return *out ? true : false;
}
int curlx_win32_open(const char *filename, int oflag, ...)
{
int pmode = 0;
int result = -1;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
#endif
va_list param;
va_start(param, oflag);
if(oflag & O_CREAT)
pmode = va_arg(param, int);
va_end(param);
#ifdef _UNICODE
if(filename_w) {
if(fix_excessive_path(filename_w, &fixed))
target = fixed;
else
target = filename_w;
result = _wopen(target, oflag, pmode);
curlx_unicodefree(filename_w);
}
else
CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
else
target = filename;
result = _open(target, oflag, pmode);
#endif
(free)(fixed);
return result;
}
FILE *curlx_win32_fopen(const char *filename, const char *mode)
{
FILE *result = NULL;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
if(filename_w && mode_w) {
if(fix_excessive_path(filename_w, &fixed))
target = fixed;
else
target = filename_w;
result = _wfopen(target, mode_w);
}
else
CURL_SETERRNO(EINVAL);
curlx_unicodefree(filename_w);
curlx_unicodefree(mode_w);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
else
target = filename;
result = fopen(target, mode);
#endif
(free)(fixed);
return result;
}
int curlx_win32_stat(const char *path, struct_stat *buffer)
{
int result = -1;
TCHAR *fixed = NULL;
const TCHAR *target = NULL;
#ifdef _UNICODE
wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
if(path_w) {
if(fix_excessive_path(path_w, &fixed))
target = fixed;
else
target = path_w;
#ifndef USE_WIN32_LARGE_FILES
result = _wstat(target, buffer);
#else
result = _wstati64(target, buffer);
#endif
curlx_unicodefree(path_w);
}
else
CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(path, &fixed))
target = fixed;
else
target = path;
#ifndef USE_WIN32_LARGE_FILES
result = _stat(target, buffer);
#else
result = _stati64(target, buffer);
#endif
#endif
(free)(fixed);
return result;
}
#endif