From 0f410f8087f44f3ce347a207f90be64ce3f64d80 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Sat, 7 Jan 2017 01:09:17 +0100 Subject: [PATCH] Fixed bug #73877 readlink() returns garbage for UTF-8 paths --- NEWS | 3 ++ Zend/zend_virtual_cwd.c | 52 ++++++++++++---------------- ext/standard/tests/dir/bug73877.phpt | 50 ++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 ext/standard/tests/dir/bug73877.phpt diff --git a/NEWS b/NEWS index d563dcc17b..8a385eebf3 100644 --- a/NEWS +++ b/NEWS @@ -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-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +string(%d) "%sbug73877" +string(%d) "%sСерёжка" +string(%d) "%sbug73877" +bool(true) + -- 2.50.1