mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fixed bug #72625 realpath() fails on non canonical long path
This commit is contained in:
parent
fc30b8e0f7
commit
0f16c56262
4 changed files with 148 additions and 7 deletions
53
ext/standard/tests/dir/bug72625.phpt
Normal file
53
ext/standard/tests/dir/bug72625.phpt
Normal file
|
@ -0,0 +1,53 @@
|
|||
--TEST--
|
||||
Bug #72625 realpath() fails on very long argument.
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (substr(PHP_OS, 0, 3) != 'WIN') {
|
||||
die("skip Valid only on Windows");
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$base = sys_get_temp_dir() . "/" . md5(uniqid());
|
||||
while (strlen($base) < 260) {
|
||||
$base = "$base/" . md5(uniqid());
|
||||
}
|
||||
|
||||
$f0 = "$base/_test/documents/projects/myproject/vendor/name/library/classpath";
|
||||
$f1 = "$f0/../../../../../../../../_test/documents/projects/myproject/vendor/name/library/../../../../../../../_test/documents/projects/myproject/vendor/name/library/classpath";
|
||||
|
||||
|
||||
mkdir($f0, 0777, true);
|
||||
|
||||
|
||||
var_dump(
|
||||
$f0,
|
||||
file_exists($f0),
|
||||
realpath($f0),
|
||||
dirname($f0),
|
||||
|
||||
$f1,
|
||||
file_exists($f1),
|
||||
realpath($f1),
|
||||
dirname($f1)
|
||||
);
|
||||
|
||||
$tmp = $f0;
|
||||
while ($tmp > $base) {
|
||||
rmdir($tmp);
|
||||
$tmp = dirname($tmp);
|
||||
}
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
string(%d) "%s/_test/documents/projects/myproject/vendor/name/library/classpath"
|
||||
bool(true)
|
||||
string(%d) "%s\_test\documents\projects\myproject\vendor\name\library\classpath"
|
||||
string(%d) "%s\_test\documents\projects\myproject\vendor\name\library"
|
||||
string(%d) "%s/_test/documents/projects/myproject/vendor/name/library/classpath/../../../../../../../../_test/documents/projects/myproject/vendor/name/library/../../../../../../../_test/documents/projects/myproject/vendor/name/library/classpath"
|
||||
bool(true)
|
||||
string(%d) "%s\_test\documents\projects\myproject\vendor\name\library\classpath"
|
||||
string(%d) "%s\_test\documents\projects\myproject\vendor\name\library"
|
||||
===DONE===
|
|
@ -19,6 +19,7 @@
|
|||
#include <config.w32.h>
|
||||
|
||||
#include <win32/time.h>
|
||||
#include <win32/ioutil.h>
|
||||
#include <php.h>
|
||||
|
||||
#ifdef HAVE_LIBXML
|
||||
|
@ -44,6 +45,12 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID dummy)
|
|||
fprintf(stderr, "gettimeofday() initialization failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ret && php_win32_ioutil_init();
|
||||
if (!ret) {
|
||||
fprintf(stderr, "ioutil initialization failed");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
#if 0 /* prepared */
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
|
|
@ -58,12 +58,18 @@
|
|||
#include "win32/ioutil.h"
|
||||
#include "win32/codepage.h"
|
||||
|
||||
#include <pathcch.h>
|
||||
|
||||
/*
|
||||
#undef NONLS
|
||||
#undef _WINNLS_
|
||||
#include <winnls.h>
|
||||
*/
|
||||
|
||||
typedef HRESULT (WINAPI *MyPathCchCanonicalizeEx)(_Out_ PWSTR pszPathOut, _In_ size_t cchPathOut, _In_ PCWSTR pszPathIn, _In_ unsigned long dwFlags);
|
||||
|
||||
static MyPathCchCanonicalizeEx canonicalize_path_w = NULL;
|
||||
|
||||
PW32IO BOOL php_win32_ioutil_posix_to_open_opts(int flags, mode_t mode, php_ioutil_open_opts *opts)
|
||||
{/*{{{*/
|
||||
int current_umask;
|
||||
|
@ -500,6 +506,62 @@ PW32IO size_t php_win32_ioutil_dirname(char *path, size_t len)
|
|||
return ret_len;
|
||||
}/*}}}*/
|
||||
|
||||
PW32IO BOOL php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len)
|
||||
{/*{{{*/
|
||||
wchar_t *pos, *idx = *buf, canonicalw[MAXPATHLEN];
|
||||
size_t ret_len = len, canonicalw_len, shift;
|
||||
|
||||
if (len >= MAXPATHLEN) {
|
||||
SET_ERRNO_FROM_WIN32_CODE(ERROR_BUFFER_OVERFLOW);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (NULL != (pos = wcschr(idx, PHP_WIN32_IOUTIL_FW_SLASHW)) && idx - *buf <= len) {
|
||||
*pos = PHP_WIN32_IOUTIL_DEFAULT_SLASHW;
|
||||
idx = pos++;
|
||||
}
|
||||
|
||||
shift = PHP_WIN32_IOUTIL_IS_LONG_PATHW(*buf, len) ? PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW : 0;
|
||||
if (S_OK != canonicalize_path_w(canonicalw, MAXPATHLEN, *buf + shift, PATHCCH_ALLOW_LONG_PATHS)) {
|
||||
*new_len = ret_len;
|
||||
return FALSE;
|
||||
}
|
||||
canonicalw_len = wcslen(canonicalw);
|
||||
if (canonicalw_len + shift != len) {
|
||||
if (canonicalw_len > len) {
|
||||
*buf = realloc(*buf, (canonicalw_len + 1) * sizeof(wchar_t));
|
||||
}
|
||||
memmove(*buf + shift, canonicalw, (canonicalw_len + 1) * sizeof(wchar_t));
|
||||
ret_len = canonicalw_len + shift;
|
||||
}
|
||||
*new_len = ret_len;
|
||||
|
||||
return TRUE;
|
||||
}/*}}}*/
|
||||
|
||||
static HRESULT MyPathCchCanonicalizeExFallback(_Out_ PWSTR pszPathOut, _In_ size_t cchPathOut, _In_ PCWSTR pszPathIn, _In_ unsigned long dwFlags)
|
||||
{
|
||||
pszPathOut = pszPathIn;
|
||||
cchPathOut = wcslen(pszPathOut);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOL php_win32_ioutil_init(void)
|
||||
{
|
||||
HMODULE hMod = GetModuleHandle("api-ms-win-core-path-l1-1-0");
|
||||
|
||||
if (hMod) {
|
||||
canonicalize_path_w = (MyPathCchCanonicalizeEx)GetProcAddress(hMod, "PathCchCanonicalizeEx");
|
||||
if (!canonicalize_path_w) {
|
||||
canonicalize_path_w = MyPathCchCanonicalizeExFallback;
|
||||
}
|
||||
} else {
|
||||
canonicalize_path_w = MyPathCchCanonicalizeExFallback;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
/* an extended version could be implemented, for now direct functions can be used. */
|
||||
#if 0
|
||||
PW32IO int php_win32_ioutil_access_w(const wchar_t *path, mode_t mode)
|
||||
|
|
|
@ -88,11 +88,15 @@ typedef enum {
|
|||
} php_win32_ioutil_encoding;
|
||||
|
||||
|
||||
#define PHP_WIN32_IOUTIL_DEFAULT_SLASHW L'\\'
|
||||
#define PHP_WIN32_IOUTIL_DEFAULT_SLASH '\\'
|
||||
#define PHP_WIN32_IOUTIL_FW_SLASHW L'/'
|
||||
#define PHP_WIN32_IOUTIL_FW_SLASH '/'
|
||||
#define PHP_WIN32_IOUTIL_BW_SLASHW L'\\'
|
||||
#define PHP_WIN32_IOUTIL_BW_SLASH '\\'
|
||||
#define PHP_WIN32_IOUTIL_DEFAULT_SLASHW PHP_WIN32_IOUTIL_BW_SLASHW
|
||||
#define PHP_WIN32_IOUTIL_DEFAULT_SLASH PHP_WIN32_IOUTIL_BW_SLASH
|
||||
|
||||
#define PHP_WIN32_IOUTIL_DEFAULT_DIR_SEPARATORW L';'
|
||||
#define PHP_WIN32_IOUTIL_IS_SLASHW(c) ((c) == L'\\' || (c) == L'/')
|
||||
#define PHP_WIN32_IOUTIL_IS_SLASHW(c) ((c) == PHP_WIN32_IOUTIL_BW_SLASHW || (c) == PHP_WIN32_IOUTIL_FW_SLASHW)
|
||||
#define PHP_WIN32_IOUTIL_IS_LETTERW(c) (((c) >= L'a' && (c) <= L'z') || ((c) >= L'A' && (c) <= L'Z'))
|
||||
#define PHP_WIN32_IOUTIL_JUNCTION_PREFIXW L"\\??\\"
|
||||
#define PHP_WIN32_IOUTIL_JUNCTION_PREFIX_LENW 4
|
||||
|
@ -129,6 +133,13 @@ typedef enum {
|
|||
} \
|
||||
} while (0);
|
||||
|
||||
PW32IO BOOL php_win32_ioutil_normalize_path_w(wchar_t **buf, size_t len, size_t *new_len);
|
||||
#ifdef PHP_EXPORTS
|
||||
/* This symbols are needed only for the DllMain, but should not be exported
|
||||
or be available when used with PHP binaries. */
|
||||
BOOL php_win32_ioutil_init(void);
|
||||
#endif
|
||||
|
||||
/* Keep these functions aliased for case some additional handling
|
||||
is needed later. */
|
||||
__forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, size_t in_len, size_t *out_len)
|
||||
|
@ -148,11 +159,19 @@ __forceinline static wchar_t *php_win32_ioutil_conv_any_to_w(const char* in, siz
|
|||
free(mb);
|
||||
return NULL;
|
||||
}
|
||||
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_PREFIX_LENW, mb, mb_len * sizeof(wchar_t));
|
||||
ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW] = L'\0';
|
||||
|
||||
mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
||||
(void)php_win32_ioutil_normalize_path_w(&mb, mb_len, &mb_len);
|
||||
|
||||
if (PHP_WIN32_IOUTIL_IS_LONG_PATHW(mb, mb_len)) {
|
||||
memmove(ret, mb, mb_len * sizeof(wchar_t));
|
||||
ret[mb_len] = L'\0';
|
||||
} else {
|
||||
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_PREFIX_LENW, mb, mb_len * sizeof(wchar_t));
|
||||
ret[mb_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW] = L'\0';
|
||||
|
||||
mb_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
|
||||
}
|
||||
|
||||
free(mb);
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue