diff options
author | Anatol Belski <ab@php.net> | 2017-09-28 13:18:31 +0200 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2017-09-28 13:18:31 +0200 |
commit | 72c008f945f964521fd5227c2a6dc32bdaaf28b9 (patch) | |
tree | 26e2d8d71da069cd9a6bb3b5dd922629f67b239d | |
parent | 1c68d63f35aecc2aa602ffc429688ed43ffb92b6 (diff) | |
download | php-git-72c008f945f964521fd5227c2a6dc32bdaaf28b9.tar.gz |
Fix mkdir() special case for path length < 260 and > 248
-rw-r--r-- | ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt | 60 | ||||
-rw-r--r-- | win32/ioutil.c | 29 |
2 files changed, 88 insertions, 1 deletions
diff --git a/ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt b/ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt new file mode 100644 index 0000000000..2453538190 --- /dev/null +++ b/ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt @@ -0,0 +1,60 @@ +--TEST-- +Mkdir with path length < 260 and > 248 has be a long path +--SKIPIF-- +<?php +include dirname(__FILE__) . DIRECTORY_SEPARATOR . "util.inc"; + +skip_if_not_win(); + +$start = realpath(dirname(__FILE__)); +if (strlen($start) > 260 || strlen($start) > 248) { + die("skip the starting path length is unsuitable for this test"); +} + +?> +--FILE-- +<?php + +$p = ""; +$s = str_repeat('a', 50); +$how_many = 32; + +for ($i = 0; $i < $how_many; $i++) { + $p .= "$s\\"; +} + +$start = realpath(dirname(__FILE__)); +if (strlen($start) <= 248) { + // create the exact length + $start = $start . "\\" . str_repeat('a', 251 - strlen($start) - 1); +} + +var_dump($start); +$p = $start . "\\" . $p; + +var_dump($p); +var_dump(mkdir($p, 0777, true)); +var_dump(file_exists($p)); + +$p7 = $p . "hello.txt"; + +var_dump(file_put_contents($p7, "hello")); +var_dump(file_get_contents($p7)); + +// cleanup +unlink($p7); +for ($i = 0; $i < $how_many; $i++) { + $p0 = substr($p, 0, strlen($p) - $i*51); + rmdir($p0); +} + +?> +===DONE=== +--EXPECTF-- +string(251) "%s" +string(1884) "%s" +bool(true) +bool(true) +int(5) +string(5) "hello" +===DONE=== diff --git a/win32/ioutil.c b/win32/ioutil.c index 6fb89c46ed..0beea2bfef 100644 --- a/win32/ioutil.c +++ b/win32/ioutil.c @@ -306,10 +306,37 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode) PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode) {/*{{{*/ - wchar_t *pathw = php_win32_ioutil_any_to_w(path); + size_t pathw_len = 0; + wchar_t *pathw = php_win32_ioutil_conv_any_to_w(path, 0, &pathw_len); int ret = 0; DWORD err = 0; + if (pathw_len < _MAX_PATH && pathw_len > _MAX_PATH - 12) { + /* Special case here. From the doc: + + "When using an API to create a directory, the specified path cannot be + so long that you cannot append an 8.3 file name ..." + + Thus, if the directory name length happens to be in this range, it + already needs to be a long path. The given path is already normalized + and prepared, need only to prefix it. + */ + wchar_t *tmp = (wchar_t *) malloc((pathw_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t)); + if (!tmp) { + free(pathw); + SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY); + return -1; + } + + memmove(tmp, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t)); + memmove(tmp+PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, pathw, pathw_len * sizeof(wchar_t)); + pathw_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW; + tmp[pathw_len] = L'\0'; + + free(pathw); + pathw = tmp; + } + /* TODO extend with mode usage */ if (!pathw) { SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER); |