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;
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;
}
/* }}} */
--- /dev/null
+--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)
+