Skip to content

Commit

Permalink
Fix mkdir() special case for path length < 260 and > 248
Browse files Browse the repository at this point in the history
  • Loading branch information
weltling committed Sep 28, 2017
1 parent 1c68d63 commit 72c008f
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
60 changes: 60 additions & 0 deletions ext/standard/tests/file/windows_mb_path/test_long_path_mkdir.phpt
Original file line number Diff line number Diff line change
@@ -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===
29 changes: 28 additions & 1 deletion win32/ioutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 72c008f

Please sign in to comment.