feature #40144 [Filesystem] Remove dirs atomically if possible (nicolas-grekas)
This PR was merged into the 5.3-dev branch.
Discussion
----------
[Filesystem] Remove dirs atomically if possible
| Q | A
| ------------- | ---
| Branch? | 5.x
| Bug fix? | no
| New feature? | no
| Deprecations? | no
| Tickets | Fix #27578
| License | MIT
| Doc PR | no need to
Commits
-------
17bccca9c6
[Filesystem] remove dirs atomically if possible
This commit is contained in:
commit
d97ab18aa6
@ -162,6 +162,12 @@ class Filesystem
|
|||||||
} elseif (!\is_array($files)) {
|
} elseif (!\is_array($files)) {
|
||||||
$files = [$files];
|
$files = [$files];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self::doRemove($files, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function doRemove(array $files, bool $isRecursive): void
|
||||||
|
{
|
||||||
$files = array_reverse($files);
|
$files = array_reverse($files);
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
if (is_link($file)) {
|
if (is_link($file)) {
|
||||||
@ -170,10 +176,35 @@ class Filesystem
|
|||||||
throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError);
|
throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError);
|
||||||
}
|
}
|
||||||
} elseif (is_dir($file)) {
|
} elseif (is_dir($file)) {
|
||||||
$this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
|
if (!$isRecursive) {
|
||||||
|
$tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-.'));
|
||||||
|
|
||||||
if (!self::box('rmdir', $file) && file_exists($file)) {
|
if (file_exists($tmpName)) {
|
||||||
throw new IOException(sprintf('Failed to remove directory "%s": ', $file).self::$lastError);
|
try {
|
||||||
|
self::doRemove([$tmpName], true);
|
||||||
|
} catch (IOException $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists($tmpName) && self::box('rename', $file, $tmpName)) {
|
||||||
|
$origFile = $file;
|
||||||
|
$file = $tmpName;
|
||||||
|
} else {
|
||||||
|
$origFile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS);
|
||||||
|
self::doRemove(iterator_to_array($files, true), true);
|
||||||
|
|
||||||
|
if (!self::box('rmdir', $file) && file_exists($file) && !$isRecursive) {
|
||||||
|
$lastError = self::$lastError;
|
||||||
|
|
||||||
|
if (null !== $origFile && self::box('rename', $file, $origFile)) {
|
||||||
|
$file = $origFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException(sprintf('Failed to remove directory "%s": ', $file).$lastError);
|
||||||
}
|
}
|
||||||
} elseif (!self::box('unlink', $file) && (false !== strpos(self::$lastError, 'Permission denied') || file_exists($file))) {
|
} elseif (!self::box('unlink', $file) && (false !== strpos(self::$lastError, 'Permission denied') || file_exists($file))) {
|
||||||
throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError);
|
throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError);
|
||||||
|
Reference in New Issue
Block a user