summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2017-09-28 13:18:31 +0200
committerAnatol Belski <ab@php.net>2017-09-28 13:18:31 +0200
commit72c008f945f964521fd5227c2a6dc32bdaaf28b9 (patch)
tree26e2d8d71da069cd9a6bb3b5dd922629f67b239d
parent1c68d63f35aecc2aa602ffc429688ed43ffb92b6 (diff)
downloadphp-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.phpt60
-rw-r--r--win32/ioutil.c29
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);