Skip to content

Commit d6747c3

Browse files
refactor(storage): simplify symlink-safe directory removal
Resolve the source path once, clear the stat cache before checking whether it is a symlink, and use an early return to avoid nesting the recursive directory removal logic. Signed-off-by: Josh <josh.t.richards@gmail.com>
1 parent 63ebd2b commit d6747c3

1 file changed

Lines changed: 41 additions & 31 deletions

File tree

lib/private/Files/Storage/Local.php

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -99,41 +99,51 @@ public function rmdir(string $path): bool {
9999
if (!$this->isDeletable($path)) {
100100
return false;
101101
}
102+
103+
$sourcePath = $this->getSourcePath($path);
104+
clearstatcache(true, $sourcePath);
105+
106+
if (is_link($sourcePath)) {
107+
return unlink($sourcePath);
108+
}
109+
102110
try {
103-
if (is_link($this->getSourcePath($path))) {
104-
clearstatcache(true, $this->getSourcePath($path));
105-
return unlink($this->getSourcePath($path));
106-
} else {
107-
$it = new \RecursiveIteratorIterator(
108-
new \RecursiveDirectoryIterator($this->getSourcePath($path)),
109-
\RecursiveIteratorIterator::CHILD_FIRST
110-
);
111-
/**
112-
* RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
113-
* This bug is fixed in PHP 5.5.9 or before
114-
* See #8376
115-
*/
116-
$it->rewind();
117-
while ($it->valid()) {
118-
/**
119-
* @var \SplFileInfo $file
120-
*/
121-
$file = $it->current();
122-
clearstatcache(true, $file->getRealPath());
123-
if (in_array($file->getBasename(), ['.', '..'])) {
124-
$it->next();
125-
continue;
126-
} elseif ($file->isFile() || $file->isLink()) {
127-
unlink($file->getPathname());
128-
} elseif ($file->isDir()) {
129-
rmdir($file->getPathname());
130-
}
111+
$it = new \RecursiveIteratorIterator(
112+
new \RecursiveDirectoryIterator($sourcePath),
113+
\RecursiveIteratorIterator::CHILD_FIRST
114+
);
115+
116+
/**
117+
* RecursiveDirectoryIterator on an NFS path isn't iterable with foreach.
118+
* This bug is fixed in PHP 5.5.9 or before.
119+
* See #8376.
120+
*/
121+
$it->rewind();
122+
while ($it->valid()) {
123+
/** @var \SplFileInfo $file */
124+
$file = $it->current();
125+
clearstatcache(true, $file->getRealPath());
126+
127+
if (in_array($file->getBasename(), ['.', '..'], true)) {
131128
$it->next();
129+
continue;
130+
}
131+
132+
if ($file->isFile() || $file->isLink()) {
133+
unlink($file->getPathname());
134+
} elseif ($file->isDir()) {
135+
rmdir($file->getPathname());
132136
}
133-
unset($it); // Release iterator and thereby its potential directory lock (e.g. in case of VirtualBox shared folders)
134-
clearstatcache(true, $this->getSourcePath($path));
135-
return rmdir($this->getSourcePath($path));
137+
138+
$it->next();
136139
}
140+
141+
// Release the iterator and its potential directory lock,
142+
// for example on VirtualBox shared folders.
143+
unset($it);
144+
145+
clearstatcache(true, $sourcePath);
146+
return rmdir($sourcePath);
137147
} catch (\UnexpectedValueException $e) {
138148
return false;
139149
}

0 commit comments

Comments
 (0)