From 72c008f945f964521fd5227c2a6dc32bdaaf28b9 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 28 Sep 2017 13:18:31 +0200 Subject: Fix mkdir() special case for path length < 260 and > 248 --- .../file/windows_mb_path/test_long_path_mkdir.phpt | 60 ++++++++++++++++++++++ win32/ioutil.c | 29 ++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt 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-- + 260 || strlen($start) > 248) { + die("skip the starting path length is unsuitable for this test"); +} + +?> +--FILE-- + +===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); -- cgit v1.2.1