mirror of
https://github.com/php/php-src.git
synced 2024-11-26 19:33:55 +08:00
Fix GH-10992: Improper long path support for relative paths
Relative paths are passed to the ioutils APIs, these are not properly converted to long paths. If the path length already exceeds a given threshold (usually 259 characters, but only 247 for `mkdir()`), the long path prefix is prepended, resulting in an invalid path, since long paths have to be absolute. If the path length does not exceed that threshold, no conversion to a long path is done, although that may be necessary. Thus we take the path length of the current working directory into account when checking the threshold, and prepend it to the filename if necessary. Since this is only relevant for NTS builds, and using the current working directory of the process would be erroneous for ZTS builds, we skip the new code for ZTS builds. Closes GH-16687.
This commit is contained in:
parent
59fe79fb45
commit
5c76ef78cb
4
NEWS
4
NEWS
@ -40,6 +40,10 @@ PHP NEWS
|
|||||||
. Fixed bug #49169 (SoapServer calls wrong function, although "SOAP action"
|
. Fixed bug #49169 (SoapServer calls wrong function, although "SOAP action"
|
||||||
header is correct). (nielsdos)
|
header is correct). (nielsdos)
|
||||||
|
|
||||||
|
- Windows:
|
||||||
|
. Fixed bug GH-10992 (Improper long path support for relative paths). (cmb,
|
||||||
|
nielsdos)
|
||||||
|
|
||||||
- XMLWriter:
|
- XMLWriter:
|
||||||
. Improved performance and reduce memory consumption. (nielsdos)
|
. Improved performance and reduce memory consumption. (nielsdos)
|
||||||
|
|
||||||
|
16
ext/standard/tests/directory/gh10992.phpt
Normal file
16
ext/standard/tests/directory/gh10992.phpt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
--TEST--
|
||||||
|
GH-10992 (Improper long path support for relative paths)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$dir = str_repeat('b', 250 - strlen(getcwd()));
|
||||||
|
var_dump(mkdir($dir));
|
||||||
|
var_dump(rmdir($dir));
|
||||||
|
$dir = str_repeat('b', 265 - strlen(getcwd()));
|
||||||
|
var_dump(mkdir($dir));
|
||||||
|
var_dump(rmdir($dir));
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
@ -281,7 +281,7 @@ PW32IO int php_win32_ioutil_close(int fd)
|
|||||||
|
|
||||||
PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
|
PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
|
||||||
{/*{{{*/
|
{/*{{{*/
|
||||||
size_t path_len;
|
size_t path_len, dir_len = 0;
|
||||||
const wchar_t *my_path;
|
const wchar_t *my_path;
|
||||||
|
|
||||||
if (!path) {
|
if (!path) {
|
||||||
@ -292,7 +292,16 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
|
|||||||
PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0)
|
PHP_WIN32_IOUTIL_CHECK_PATH_W(path, -1, 0)
|
||||||
|
|
||||||
path_len = wcslen(path);
|
path_len = wcslen(path);
|
||||||
if (path_len < _MAX_PATH && path_len >= _MAX_PATH - 12) {
|
#ifndef ZTS
|
||||||
|
if (!PHP_WIN32_IOUTIL_IS_ABSOLUTEW(path, path_len) && !PHP_WIN32_IOUTIL_IS_JUNCTION_PATHW(path, path_len) && !PHP_WIN32_IOUTIL_IS_UNC_PATHW(path, path_len)) {
|
||||||
|
dir_len = GetCurrentDirectoryW(0, NULL);
|
||||||
|
if (dir_len == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (dir_len + path_len < _MAX_PATH && dir_len + path_len >= _MAX_PATH - 12) {
|
||||||
/* Special case here. From the doc:
|
/* Special case here. From the doc:
|
||||||
|
|
||||||
"When using an API to create a directory, the specified path cannot be
|
"When using an API to create a directory, the specified path cannot be
|
||||||
@ -315,7 +324,7 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!PHP_WIN32_IOUTIL_IS_LONG_PATHW(tmp, path_len)) {
|
if (!PHP_WIN32_IOUTIL_IS_LONG_PATHW(tmp, path_len)) {
|
||||||
wchar_t *_tmp = (wchar_t *) malloc((path_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
|
wchar_t *_tmp = (wchar_t *) malloc((dir_len + path_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
|
||||||
wchar_t *src, *dst;
|
wchar_t *src, *dst;
|
||||||
if (!_tmp) {
|
if (!_tmp) {
|
||||||
SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
@ -325,6 +334,18 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
|
|||||||
memmove(_tmp, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
|
memmove(_tmp, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
|
||||||
src = tmp;
|
src = tmp;
|
||||||
dst = _tmp + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
dst = _tmp + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
||||||
|
#ifndef ZTS
|
||||||
|
if (dir_len > 0) {
|
||||||
|
size_t len = GetCurrentDirectoryW(dir_len, dst);
|
||||||
|
if (len == 0 || len + 1 != dir_len) {
|
||||||
|
free(tmp);
|
||||||
|
free(_tmp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dst += len;
|
||||||
|
*dst++ = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
while (src < tmp + path_len) {
|
while (src < tmp + path_len) {
|
||||||
if (*src == PHP_WIN32_IOUTIL_FW_SLASHW) {
|
if (*src == PHP_WIN32_IOUTIL_FW_SLASHW) {
|
||||||
*dst++ = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
*dst++ = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
||||||
@ -333,7 +354,7 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
|
|||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
path_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
path_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + dir_len;
|
||||||
_tmp[path_len] = L'\0';
|
_tmp[path_len] = L'\0';
|
||||||
free(tmp);
|
free(tmp);
|
||||||
tmp = _tmp;
|
tmp = _tmp;
|
||||||
|
@ -175,18 +175,28 @@ PW32IO php_win32_ioutil_normalization_result php_win32_ioutil_normalize_path_w(w
|
|||||||
__forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, size_t in_len, size_t *out_len)
|
__forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, size_t in_len, size_t *out_len)
|
||||||
{/*{{{*/
|
{/*{{{*/
|
||||||
wchar_t *mb, *ret;
|
wchar_t *mb, *ret;
|
||||||
size_t mb_len;
|
size_t mb_len, dir_len = 0;
|
||||||
|
|
||||||
mb = php_win32_cp_conv_any_to_w(in, in_len, &mb_len);
|
mb = php_win32_cp_conv_any_to_w(in, in_len, &mb_len);
|
||||||
if (!mb) {
|
if (!mb) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ZTS
|
||||||
|
if (!PHP_WIN32_IOUTIL_IS_ABSOLUTEW(mb, mb_len) && !PHP_WIN32_IOUTIL_IS_JUNCTION_PATHW(mb, mb_len) && !PHP_WIN32_IOUTIL_IS_UNC_PATHW(mb, mb_len)) {
|
||||||
|
dir_len = GetCurrentDirectoryW(0, NULL);
|
||||||
|
if (dir_len == 0) {
|
||||||
|
free(mb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Only prefix with long if it's needed. */
|
/* Only prefix with long if it's needed. */
|
||||||
if (mb_len >= _MAX_PATH) {
|
if (dir_len + mb_len >= _MAX_PATH) {
|
||||||
size_t new_mb_len;
|
size_t new_mb_len;
|
||||||
|
|
||||||
ret = (wchar_t *) malloc((mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
|
ret = (wchar_t *) malloc((dir_len + mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
free(mb);
|
free(mb);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -199,7 +209,7 @@ __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new_mb_len > mb_len) {
|
if (new_mb_len > mb_len) {
|
||||||
wchar_t *tmp = (wchar_t *) realloc(ret, (new_mb_len + 1) * sizeof(wchar_t));
|
wchar_t *tmp = (wchar_t *) realloc(ret, (dir_len + new_mb_len + 1) * sizeof(wchar_t));
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
free(ret);
|
free(ret);
|
||||||
free(mb);
|
free(mb);
|
||||||
@ -215,6 +225,18 @@ __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, siz
|
|||||||
} else {
|
} else {
|
||||||
wchar_t *src = mb, *dst = ret + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
wchar_t *src = mb, *dst = ret + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
||||||
memmove(ret, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
|
memmove(ret, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
|
||||||
|
#ifndef ZTS
|
||||||
|
if (dir_len > 0) {
|
||||||
|
size_t len = GetCurrentDirectoryW(dir_len, dst);
|
||||||
|
if (len == 0 || len + 1 != dir_len) {
|
||||||
|
free(ret);
|
||||||
|
free(mb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dst += len;
|
||||||
|
*dst++ = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
while (src < mb + mb_len) {
|
while (src < mb + mb_len) {
|
||||||
if (*src == PHP_WIN32_IOUTIL_FW_SLASHW) {
|
if (*src == PHP_WIN32_IOUTIL_FW_SLASHW) {
|
||||||
*dst++ = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
*dst++ = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
||||||
@ -223,9 +245,9 @@ __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, siz
|
|||||||
*dst++ = *src++;
|
*dst++ = *src++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW] = L'\0';
|
ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + dir_len] = L'\0';
|
||||||
|
|
||||||
mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + dir_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mb);
|
free(mb);
|
||||||
|
Loading…
Reference in New Issue
Block a user