10000 Update FileSystem · symfony/symfony@41a16e2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 41a16e2

Browse files
committed
Update FileSystem
* Fixes edge case on windows where PHP does not generate a PHP Warning but instead returns a wrong result https://bugs.php.net/bug.php?id=71103 * Improved error reporting on `unlink` used in `remove()`
1 parent c2cad23 commit 41a16e2

File tree

2 files changed

+53
-3
lines changed

2 files changed

+53
-3
lines changed

src/Symfony/Component/Filesystem/Filesystem.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ public function mkdir($dirs, $mode = 0777)
100100
public function exists($files)
101101
{
102102
foreach ($this->toIterator($files) as $file) {
103+
if ('\\' === DIRECTORY_SEPARATOR AND strlen((string) $file) > 258) {
104+
throw new IOException(sprintf('Could not check if file exist because path length exceeds 258 characters for file "%s"', $file));
105+
}
106+
103107
if (!file_exists($file)) {
104108
return false;
105109
}
@@ -139,7 +143,7 @@ public function remove($files)
139143
$files = iterator_to_array($this->toIterator($files));
140144
$files = array_reverse($files);
141145
foreach ($files as $file) {
142-
if (!file_exists($file) && !is_link($file)) {
146+
if (!$this->exists($file) && !is_link($file)) {
143147
continue;
144148
}
145149

@@ -157,7 +161,8 @@ public function remove($files)
157161
}
158162
} else {
159163
if (true !== @unlink($file)) {
160-
throw new IOException(sprintf('Failed to remove file %s', $file));
164+
$error = error_get_last();
165+
throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message']));
161166
}
162167
}
163168
}
@@ -253,7 +258,7 @@ public function chgrp($files, $group, $recursive = false)
253258
public function rename($origin, $target, $overwrite = false)
254259
{
255260
// we check that target does not exist
256-
if (!$overwrite && is_readable($target)) {
261+
if (!$overwrite && $this->isReadable($target)) {
257262
throw new IOException(sprintf('Cannot rename because the target "%s" already exist.', $target));
258263
}
259264

@@ -262,6 +267,22 @@ public function rename($origin, $target, $overwrite = false)
262267
}
263268
}
264269

270+
/**
271+
* Tells whether a file exists and is readable.
272+
*
273+
* @param string $filename Path to the file.
274+
*
275+
* @throws IOException When windows path is longer than 258 characters
276+
*/
277+
private function isReadable($filename)
278+
{
279+
if ('\\' === DIRECTORY_SEPARATOR AND strlen((string) $filename) > 258) {
280+
throw new IOException(sprintf('Could not check if file is readable because path length exceeds 258 characters for file "%s"', $filename), 0, null, $filename);
281+
}
282+
283+
return is_readable($filename);
284+
}
285+
265286
/**
266287
* Creates a symbolic link or copy a directory.
267288
*

src/Symfony/Component/Filesystem/Tests/FilesystemTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
class FilesystemTest extends \PHPUnit_Framework_TestCase
2020
{
2121
private $umask;
22+
private $longPathNamesWindows = array();
2223

2324
/**
2425
* @var string
@@ -56,6 +57,12 @@ protected function setUp()
5657

5758
protected function tearDown()
5859
{
60+
if (!empty($this->longPathNamesWindows)) {
61+
foreach ($this->longPathNamesWindows as $path) {
62+
exec('DEL '.$path);
63+
}
64+
}
65+
5966
$this->filesystem->remove($this->workspace);
6067
umask($this->umask);
6168
}
@@ -354,6 +361,28 @@ public function testFilesExists()
354361
$this->assertTrue($this->filesystem->exists($basePath.'folder'));
355362
}
356363

364+
/**
365+
* @expectedException \Symfony\Component\Filesystem\Exception\IOException
366+
*/
367+
public function testFilesExistsFails()
368+
{
369+
if ('\\' !== DIRECTORY_SEPARATOR) {
370+
$this->markTestSkipped('Test covers edge case on Windows only.');
371+
}
372+
373+
$basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
374+
375+
$oldPath = getcwd();
376+
mkdir($basePath);
377+
chdir($basePath);
378+
$file = str_repeat('T', 259 - strlen($basePath));
379+
$path = $basePath.$file;
380+
exec('TYPE NUL >>'.$file); // equivalent of touch, we can not use the php touch() here because it suffers from the same limitation
381+
$this->longPathNamesWindows[] = $path; // save this so we can clean up later
382+
chdir($oldPath);
383+
$this->filesystem->exists($path);
384+
}
385+
357386
public function testFilesExistsTraversableObjectOfFilesAndDirectories()
358387
{
359388
$basePath = $this->workspace.DIRECTORY_SEPARATOR;

0 commit comments

Comments
 (0)
0