Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Finder] [Iterator] [SortableIterator] closure causes unintended file lock in Windows #33400

Closed
@jspringe

Description

@jspringe

Symfony version(s) affected: 4.*

Description
When using the sortByName on Finder there is an unintended file lock in Windows. This
does not release until the application ceases execution. This is due to the __construct building
an anonymous function and storing at as a property on $sort.

This gets in the way when doing a recursive directory deletion and causes a Permission Denied on Windows.

How to reproduce

class FinderBug
{
    public function unsortedFiles($path)
    {
        return iterator_to_array(Finder::create()->files()->ignoreDotFiles(true)->in($path)->depth(0), false);
    }

    public function sortedFiles($path)
    {
        return iterator_to_array(
            Finder::create()->files()->ignoreDotFiles(true)->in($path)->depth(0)->sortByName(),
            false
        );
    }

    public function deleteDirectoryRecursive($directory, bool $sorted = false)
    {
        $items = $sorted ? $this->sortedFiles($directory) : $this->unsortedFiles($directory);

        foreach ($items as $item) {
            if ($item->isDir()) {
                $this->deleteDirectoryRecursive($item->getPathname(), $sorted);
            } else {
                @unlink($item->getPathname());
            }
        }

        @rmdir($directory);
    }
}

$tempDir = __DIR__ . '/temp';
mkdir($tempDir);
mkdir($tempDir . '/foo');
touch($tempDir.'/foo/1.txt');
$bug = new FinderBug;
$bug->deleteDirectoryRecursive($tempDir . '/foo', false);
$bug->deleteDirectoryRecursive($tempDir, false);
dump(is_dir($tempDir)); // Returns false as expected

mkdir($tempDir);
mkdir($tempDir . '/foo');
touch($tempDir.'/foo/1.txt');
$bug->deleteDirectoryRecursive($tempDir . '/foo', true);
$bug->deleteDirectoryRecursive($tempDir, true);
dump(is_dir($tempDir)); // Return true due to errors.

Possible Solution
Don't store the closure as a property on SortableIterator. Instead make it a method. It's already noted that this is a potentially slow operation, and I don't believe making this a calculated on the fly value would really make any difference.

Additional context
This is related to a bug that has been chased for months in the Laravel Test Suite for Windows. I'm like 1 of 5 people who develop in PHP on Windows.. so it's been slow moving.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions