feature #30116 [Filesystem] Fix mirroring a directory into itself or in his child with realpath checks (Fleuv, XuruDragon)
This PR was merged into the 4.3-dev branch. Discussion ---------- [Filesystem] Fix mirroring a directory into itself or in his child with realpath checks | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | none / PR #29857 | License | MIT | Doc PR | n/a This this the continuity of #29857 by @Fleuv Fix a bug while trying to mirror a directory into itself or in a child Adding handle real path checks when mirroring. Commits -------8011f494d4
Handling relative/absolute path59437a4af9
Skipping iterations in the mirror() method where the iterated file's path name is equal to the target path
This commit is contained in:
commit
e92c120f27
@ -541,6 +541,10 @@ class Filesystem
|
|||||||
$originDir = rtrim($originDir, '/\\');
|
$originDir = rtrim($originDir, '/\\');
|
||||||
$originDirLen = \strlen($originDir);
|
$originDirLen = \strlen($originDir);
|
||||||
|
|
||||||
|
if (!$this->exists($originDir)) {
|
||||||
|
throw new IOException(sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir);
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate in destination folder to remove obsolete entries
|
// Iterate in destination folder to remove obsolete entries
|
||||||
if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
|
if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
|
||||||
$deleteIterator = $iterator;
|
$deleteIterator = $iterator;
|
||||||
@ -564,35 +568,24 @@ class Filesystem
|
|||||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
|
$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->exists($originDir)) {
|
$this->mkdir($targetDir);
|
||||||
$this->mkdir($targetDir);
|
$targetDirInfo = new \SplFileInfo($targetDir);
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($iterator as $file) {
|
foreach ($iterator as $file) {
|
||||||
if (false === strpos($file->getPath(), $originDir)) {
|
if ($file->getPathName() === $targetDir || $file->getRealPath() === $targetDir || 0 === strpos($file->getRealPath(), $targetDirInfo->getRealPath())) {
|
||||||
throw new IOException(sprintf('Unable to mirror "%s" directory. If the origin directory is relative, try using "realpath" before calling the mirror method.', $originDir), 0, null, $originDir);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$target = $targetDir.substr($file->getPathname(), $originDirLen);
|
$target = $targetDir.substr($file->getPathname(), $originDirLen);
|
||||||
|
|
||||||
if ($copyOnWindows) {
|
if (!$copyOnWindows && is_link($file)) {
|
||||||
if (is_file($file)) {
|
$this->symlink($file->getLinkTarget(), $target);
|
||||||
$this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
|
} elseif (is_dir($file)) {
|
||||||
} elseif (is_dir($file)) {
|
$this->mkdir($target);
|
||||||
$this->mkdir($target);
|
} elseif (is_file($file)) {
|
||||||
} else {
|
$this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
|
||||||
throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (is_link($file)) {
|
throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
|
||||||
$this->symlink($file->getLinkTarget(), $target);
|
|
||||||
} elseif (is_dir($file)) {
|
|
||||||
$this->mkdir($target);
|
|
||||||
} elseif (is_file($file)) {
|
|
||||||
$this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
|
|
||||||
} else {
|
|
||||||
throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1332,44 +1332,34 @@ class FilesystemTest extends FilesystemTestCase
|
|||||||
$this->assertFileNotExists($targetPath.'target');
|
$this->assertFileNotExists($targetPath.'target');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMirrorWithCustomIterator()
|
public function testMirrorAvoidCopyingTargetDirectoryIfInSourceDirectory()
|
||||||
{
|
{
|
||||||
$sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR;
|
$sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR;
|
||||||
|
$directory = $sourcePath.'directory'.\DIRECTORY_SEPARATOR;
|
||||||
|
$file1 = $directory.'file1';
|
||||||
|
$file2 = $sourcePath.'file2';
|
||||||
|
|
||||||
mkdir($sourcePath);
|
mkdir($sourcePath);
|
||||||
|
mkdir($directory);
|
||||||
|
file_put_contents($file1, 'FILE1');
|
||||||
|
file_put_contents($file2, 'FILE2');
|
||||||
|
|
||||||
$file = $sourcePath.\DIRECTORY_SEPARATOR.'file';
|
$targetPath = $sourcePath.'target'.\DIRECTORY_SEPARATOR;
|
||||||
file_put_contents($file, 'FILE');
|
|
||||||
|
|
||||||
$targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR;
|
if ('\\' !== \DIRECTORY_SEPARATOR) {
|
||||||
|
$this->filesystem->symlink($targetPath, $sourcePath.'target_simlink');
|
||||||
|
}
|
||||||
|
|
||||||
$splFile = new \SplFileInfo($file);
|
$this->filesystem->mirror($sourcePath, $targetPath, null, ['delete' => true]);
|
||||||
$iterator = new \ArrayObject([$splFile]);
|
|
||||||
|
|
||||||
$this->filesystem->mirror($sourcePath, $targetPath, $iterator);
|
$this->assertTrue($this->filesystem->exists($targetPath));
|
||||||
|
$this->assertTrue($this->filesystem->exists($targetPath.'directory'));
|
||||||
|
|
||||||
$this->assertTrue(is_dir($targetPath));
|
$this->assertFileEquals($file1, $targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1');
|
||||||
$this->assertFileEquals($file, $targetPath.\DIRECTORY_SEPARATOR.'file');
|
$this->assertFileEquals($file2, $targetPath.'file2');
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$this->assertFalse($this->filesystem->exists($targetPath.'target_simlink'));
|
||||||
* @expectedException \Symfony\Component\Filesystem\Exception\IOException
|
$this->assertFalse($this->filesystem->exists($targetPath.'target'));
|
||||||
* @expectedExceptionMessageRegExp /Unable to mirror "(.*)" directory/
|
|
||||||
*/
|
|
||||||
public function testMirrorWithCustomIteratorWithRelativePath()
|
|
||||||
{
|
|
||||||
$sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR;
|
|
||||||
$realSourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR;
|
|
||||||
mkdir($realSourcePath);
|
|
||||||
|
|
||||||
$file = $realSourcePath.'file';
|
|
||||||
file_put_contents($file, 'FILE');
|
|
||||||
|
|
||||||
$targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR;
|
|
||||||
|
|
||||||
$splFile = new \SplFileInfo($file);
|
|
||||||
$iterator = new \ArrayObject([$splFile]);
|
|
||||||
|
|
||||||
$this->filesystem->mirror($sourcePath, $targetPath, $iterator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user