]> granicus.if.org Git - php/commitdiff
Fix mkdir() special case for path length < 260 and > 248
authorAnatol Belski <ab@php.net>
Thu, 28 Sep 2017 11:18:31 +0000 (13:18 +0200)
committerAnatol Belski <ab@php.net>
Thu, 28 Sep 2017 11:18:31 +0000 (13:18 +0200)
ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt [new file with mode: 0644]
win32/ioutil.c

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 (file)
index 0000000..2453538
--- /dev/null
@@ -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===
index 6fb89c46ed60480d06d0e6f40d16e7ffb21e7d98..0beea2bfefd6412fc757a206e16ccaef8b891ef9 100644 (file)
@@ -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);