diff options
author | Anatol Belski <ab@php.net> | 2017-01-07 01:09:17 +0100 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2017-01-07 01:09:17 +0100 |
commit | 0f410f8087f44f3ce347a207f90be64ce3f64d80 (patch) | |
tree | bb93398967bf6dea455cbca3798cc58bda026b2c | |
parent | f8518ba1a1ecfeff10394e2ac27c580a60c0f981 (diff) | |
download | php-git-0f410f8087f44f3ce347a207f90be64ce3f64d80.tar.gz |
Fixed bug #73877 readlink() returns garbage for UTF-8 paths
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | Zend/zend_virtual_cwd.c | 52 | ||||
-rw-r--r-- | ext/standard/tests/dir/bug73877.phpt | 50 |
3 files changed, 75 insertions, 30 deletions
@@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 2017, PHP 7.1.2 +- Core: + . Fixed bug #73877 (readlink() returns garbage for UTF-8 paths). (Anatol) + - OpenSSL: . Fixed bug #71519 (add serial hex to return value array). (xrobau) diff --git a/Zend/zend_virtual_cwd.c b/Zend/zend_virtual_cwd.c index c159bb93d9..5ab3d54315 100644 --- a/Zend/zend_virtual_cwd.c +++ b/Zend/zend_virtual_cwd.c @@ -219,10 +219,9 @@ static inline time_t FileTimeToUnixTime(const FILETIME *FileTime) CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){ /* {{{ */ HANDLE hFile; - DWORD dwRet; wchar_t *linkw = php_win32_ioutil_any_to_w(link), targetw[MAXPATHLEN]; - size_t _tmp_len; - char *_tmp; + size_t ret_len, targetw_len, offset = 0; + char *ret; if (!linkw) { return -1; @@ -251,46 +250,39 @@ CWD_API int php_sys_readlink(const char *link, char *target, size_t target_len){ with VS2012 and earlier, and seems not to be fixed till now. Thus, correcting target_len so it's suddenly don't overflown. */ - dwRet = GetFinalPathNameByHandleW(hFile, targetw, MAXPATHLEN, VOLUME_NAME_DOS); - if(dwRet >= target_len || dwRet >= MAXPATHLEN || dwRet == 0) { + targetw_len = GetFinalPathNameByHandleW(hFile, targetw, MAXPATHLEN, VOLUME_NAME_DOS); + if(targetw_len >= target_len || targetw_len >= MAXPATHLEN || targetw_len == 0) { free(linkw); CloseHandle(hFile); return -1; } - _tmp = php_win32_ioutil_conv_w_to_any(targetw, dwRet, &_tmp_len); - if (!_tmp || _tmp_len >= MAXPATHLEN) { + if(targetw_len > 4) { + /* Skip first 4 characters if they are "\\?\" */ + if(targetw[0] == L'\\' && targetw[1] == L'\\' && targetw[2] == L'?' && targetw[3] == L'\\') { + offset = 4; + + /* \\?\UNC\ */ + if (targetw_len > 7 && targetw[4] == L'U' && targetw[5] == L'N' && targetw[6] == L'C') { + offset += 2; + targetw[offset] = L'\\'; + } + } + } + + ret = php_win32_ioutil_conv_w_to_any(targetw + offset, targetw_len - offset, &ret_len); + if (!ret || ret_len >= MAXPATHLEN) { CloseHandle(hFile); free(linkw); return -1; } - memcpy(target, _tmp, _tmp_len); - free(_tmp); + memcpy(target, ret, ret_len + 1); + free(ret); CloseHandle(hFile); free(linkw); - if(dwRet > 4) { - /* Skip first 4 characters if they are "\??\" */ - if(target[0] == '\\' && target[1] == '\\' && target[2] == '?' && target[3] == '\\') { - char tmp[MAXPATHLEN]; - unsigned int offset = 4; - dwRet -= 4; - - /* \??\UNC\ */ - if (dwRet > 7 && target[4] == 'U' && target[5] == 'N' && target[6] == 'C') { - offset += 2; - dwRet -= 2; - target[offset] = '\\'; - } - - memcpy(tmp, target + offset, dwRet); - memcpy(target, tmp, dwRet); - } - } - - target[dwRet] = '\0'; - return dwRet; + return ret_len; } /* }}} */ diff --git a/ext/standard/tests/dir/bug73877.phpt b/ext/standard/tests/dir/bug73877.phpt new file mode 100644 index 0000000000..bade168b4a --- /dev/null +++ b/ext/standard/tests/dir/bug73877.phpt @@ -0,0 +1,50 @@ +--TEST-- +Bug #73877 readlink() returns garbage for UTF-8 paths +File type functions +--SKIPIF-- +<?php +if (substr(PHP_OS, 0, 3) != 'WIN') { + die('skip only for Windows'); +} +?> +--FILE-- +<?php + +$base = dirname(__FILE__) . DIRECTORY_SEPARATOR . "bug73877"; +$dir0 = $base . DIRECTORY_SEPARATOR . "bug73877"; +$dir1 = $base . DIRECTORY_SEPARATOR . "Серёжка"; +$junk0 = $base . DIRECTORY_SEPARATOR . "Серёжка2"; + +mkdir($base); +mkdir($dir0); +mkdir($dir1); +`mklink /J $junk0 $dir0`; + +var_dump( + readlink($dir0), + readlink($dir1), + readlink($junk0), + strlen(readlink($dir0)) === strlen(readlink($junk0)) +); + +?> +--CLEAN-- +<?php + +$base = dirname(__FILE__) . DIRECTORY_SEPARATOR . "bug73877"; +$dir0 = $base . DIRECTORY_SEPARATOR . "bug73877"; +$dir1 = $base . DIRECTORY_SEPARATOR . "Серёжка"; +$junk0 = $base . DIRECTORY_SEPARATOR . "Серёжка2"; + +rmdir($junk0); +rmdir($dir0); +rmdir($dir1); +rmdir($base); + +?> +--EXPECTF-- +string(%d) "%sbug73877" +string(%d) "%sСерёжка" +string(%d) "%sbug73877" +bool(true) + |