Skip to content

Commit 4f63024

Browse files
committed
Merge branch 'PHP-7.1' into PHP-7.2
* PHP-7.1: Fix mkdir() special case for path length < 260 and > 248
2 parents b0d6d27 + 72c008f commit 4f63024

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
Mkdir with path length < 260 and > 248 has be a long path
3+
--SKIPIF--
4+
<?php
5+
include dirname(__FILE__) . DIRECTORY_SEPARATOR . "util.inc";
6+
7+
skip_if_not_win();
8+
9+
$start = realpath(dirname(__FILE__));
10+
if (strlen($start) > 260 || strlen($start) > 248) {
11+
die("skip the starting path length is unsuitable for this test");
12+
}
13+
14+
?>
15+
--FILE--
16+
<?php
17+
18+
$p = "";
19+
$s = str_repeat('a', 50);
20+
$how_many = 32;
21+
22+
for ($i = 0; $i < $how_many; $i++) {
23+
$p .= "$s\\";
24+
}
25+
26+
$start = realpath(dirname(__FILE__));
27+
if (strlen($start) <= 248) {
28+
// create the exact length
29+
$start = $start . "\\" . str_repeat('a', 251 - strlen($start) - 1);
30+
}
31+
32+
var_dump($start);
33+
$p = $start . "\\" . $p;
34+
35+
var_dump($p);
36+
var_dump(mkdir($p, 0777, true));
37+
var_dump(file_exists($p));
38+
39+
$p7 = $p . "hello.txt";
40+
41+
var_dump(file_put_contents($p7, "hello"));
42+
var_dump(file_get_contents($p7));
43+
44+
// cleanup
45+
unlink($p7);
46+
for ($i = 0; $i < $how_many; $i++) {
47+
$p0 = substr($p, 0, strlen($p) - $i*51);
48+
rmdir($p0);
49+
}
50+
51+
?>
52+
===DONE===
53+
--EXPECTF--
54+
string(251) "%s"
55+
string(1884) "%s"
56+
bool(true)
57+
bool(true)
58+
int(5)
59+
string(5) "hello"
60+
===DONE===

win32/ioutil.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,37 @@ PW32IO int php_win32_ioutil_mkdir_w(const wchar_t *path, mode_t mode)
306306

307307
PW32IO int php_win32_ioutil_mkdir(const char *path, mode_t mode)
308308
{/*{{{*/
309-
wchar_t *pathw = php_win32_ioutil_any_to_w(path);
309+
size_t pathw_len = 0;
310+
wchar_t *pathw = php_win32_ioutil_conv_any_to_w(path, 0, &pathw_len);
310311
int ret = 0;
311312
DWORD err = 0;
312313

314+
if (pathw_len < _MAX_PATH && pathw_len > _MAX_PATH - 12) {
315+
/* Special case here. From the doc:
316+
317+
"When using an API to create a directory, the specified path cannot be
318+
so long that you cannot append an 8.3 file name ..."
319+
320+
Thus, if the directory name length happens to be in this range, it
321+
already needs to be a long path. The given path is already normalized
322+
and prepared, need only to prefix it.
323+
*/
324+
wchar_t *tmp = (wchar_t *) malloc((pathw_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW + 1) * sizeof(wchar_t));
325+
if (!tmp) {
326+
free(pathw);
327+
SET_ERRNO_FROM_WIN32_CODE(ERROR_NOT_ENOUGH_MEMORY);
328+
return -1;
329+
}
330+
331+
memmove(tmp, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW, PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW * sizeof(wchar_t));
332+
memmove(tmp+PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, pathw, pathw_len * sizeof(wchar_t));
333+
pathw_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
334+
tmp[pathw_len] = L'\0';
335+
336+
free(pathw);
337+
pathw = tmp;
338+
}
339+
313340
/* TODO extend with mode usage */
314341
if (!pathw) {
315342
SET_ERRNO_FROM_WIN32_CODE(ERROR_INVALID_PARAMETER);

0 commit comments

Comments
 (0)