Browse Source

Fixed RecursiveDirectoryIterator with long path or with edge case length

The search path needs to be appended with the wild card. Till now, an
edge case existed, so then if a path is 259 bytes long, which is smaller
_MAX_PATH, the suffix would cause the final search path to become longer
than _MAX_PATH. It is an edge case, when the starting path happens to
have a specific length. If the starting path was longer than _MAX_PATH
or the addition of "\\*" would not exceed _MAX_PATH, the function was
correct. Except for rewind, which was broken in the case of the long
path.
PHP-7.1.21
Anatol Belski 8 years ago
parent
commit
99fe18503a
  1. 65
      ext/standard/tests/file/windows_mb_path/recursive_it.phpt
  2. 47
      win32/readdir.c

65
ext/standard/tests/file/windows_mb_path/recursive_it.phpt

@ -0,0 +1,65 @@
--TEST--
RecursiveDirectoryIterator with dir path long or of edge case length
--SKIPIF--
<?php
include dirname(__FILE__) . DIRECTORY_SEPARATOR . "util.inc";
skip_if_not_win();
if (strlen(dirname(__FILE__)) > 259) die("Unsuitable starting path length");
?>
--FILE--
<?php
$need_len = 1024;
//$need_len = 259;
$dir = dirname(__FILE__);
while ($need_len - strlen($dir) > 32) {
$dir .= DIRECTORY_SEPARATOR . str_repeat("a", 32);
}
$dir .= DIRECTORY_SEPARATOR . str_repeat("a", $need_len - strlen($dir));
mkdir($dir, 0700, true);
$fl = $dir . DIRECTORY_SEPARATOR . "hello.txt";
file_put_contents($fl, "");
$start = substr($dir, 0, strpos($dir, DIRECTORY_SEPARATOR, strlen(dirname(__FILE__))+1));
$iter = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$start,
FilesystemIterator::SKIP_DOTS
),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iter as $item) {
if (!$item->isDir()) {
var_dump($item->getPathname());
}
}
$iter->rewind();
foreach ($iter as $item) {
if ($item->isDir()) {
rmdir($item->getPathname());
} else {
unlink($item->getPathname());
}
}
rmdir($start);
var_dump(file_exists($start));
/*unlink($fl);
do {
rmdir($dir);
$dir = dirname($dir);
} while (dirname(__FILE__) != $dir);*/
?>
==DONE==
--EXPECTF--
string(%d) "%shello.txt"
bool(false)
==DONE==

47
win32/readdir.c

@ -39,9 +39,9 @@ DIR *opendir(const char *dir)
DIR *dp;
wchar_t *filespecw, *resolvedw;
HANDLE handle;
int index;
char resolved_path_buff[MAXPATHLEN];
size_t resolvedw_len, filespecw_len;
size_t resolvedw_len, filespecw_len, index;
zend_bool might_need_prefix;
if (!VCWD_REALPATH(dir, resolved_path_buff)) {
return NULL;
@ -58,7 +58,12 @@ DIR *opendir(const char *dir)
return NULL;
}
might_need_prefix = resolvedw_len >= 3 && PHP_WIN32_IOUTIL_IS_LETTERW(resolvedw[0]) && L':' == resolvedw[1] && PHP_WIN32_IOUTIL_IS_SLASHW(resolvedw[2]);
filespecw_len = resolvedw_len + 2;
if (filespecw_len >= _MAX_PATH && might_need_prefix) {
filespecw_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
}
filespecw = (wchar_t *)malloc((filespecw_len + 1)*sizeof(wchar_t));
if (filespecw == NULL) {
free(dp);
@ -66,8 +71,14 @@ DIR *opendir(const char *dir)
return NULL;
}
wcscpy(filespecw, resolvedw);
index = (int)filespecw_len - 1;
if (filespecw_len >= _MAX_PATH && might_need_prefix) {
wcscpy(filespecw, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW);
wcscpy(filespecw + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, resolvedw);
index = resolvedw_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW - 1;
} else {
wcscpy(filespecw, resolvedw);
index = resolvedw_len - 1;
}
if (index >= 0 && filespecw[index] == L'/' || index == 0 && filespecw[index] == L'\\')
filespecw[index] = L'\0';
wcscat(filespecw, L"\\*");
@ -186,24 +197,42 @@ int rewinddir(DIR *dp)
/* Re-set to the beginning */
wchar_t *filespecw;
HANDLE handle;
int index;
size_t dirw_len, filespecw_len, index;
zend_bool might_need_prefix;
FindClose(dp->handle);
dp->offset = 0;
dp->finished = 0;
filespecw = (wchar_t *)malloc((wcslen((wchar_t *)dp->dirw) + 2 + 1)*sizeof(wchar_t));
/* XXX save the dir len into the struct. */
dirw_len = wcslen((wchar_t *)dp->dirw);
might_need_prefix = dirw_len >= 3 && PHP_WIN32_IOUTIL_IS_LETTERW(dp->dirw[0]) && L':' == dp->dirw[1] && PHP_WIN32_IOUTIL_IS_SLASHW(dp->dirw[2]);
filespecw_len = dirw_len + 2;
if (filespecw_len >= _MAX_PATH && might_need_prefix) {
filespecw_len += PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW;
}
filespecw = (wchar_t *)malloc((filespecw_len + 1)*sizeof(wchar_t));
if (filespecw == NULL) {
return -1;
}
wcscpy(filespecw, (wchar_t *)dp->dirw);
index = (int)wcslen(filespecw) - 1;
if (filespecw_len >= _MAX_PATH && might_need_prefix) {
wcscpy(filespecw, PHP_WIN32_IOUTIL_LONG_PATH_PREFIXW);
wcscpy(filespecw + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW, dp->dirw);
index = dirw_len + PHP_WIN32_IOUTIL_LONG_PATH_PREFIX_LENW - 1;
} else {
wcscpy(filespecw, dp->dirw);
index = dirw_len - 1;
}
if (index >= 0 && (filespecw[index] == L'/' ||
(filespecw[index] == L'\\' && index == 0)))
filespecw[index] = L'\0';
wcscat(filespecw, L"/*");
wcscat(filespecw, L"\\*");
if ((handle = FindFirstFileW(filespecw, &(dp->fileinfo))) == INVALID_HANDLE_VALUE) {
dp->finished = 1;

Loading…
Cancel
Save