Fixed bug #73877 readlink() returns garbage for UTF-8 paths

This commit is contained in:
Anatol Belski 2017-01-07 01:09:17 +01:00
parent f8518ba1a1
commit 0f410f8087
3 changed files with 75 additions and 30 deletions

3
NEWS
View file

@ -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)

View file

@ -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;
}
/* }}} */

View file

@ -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)