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

Skip to content

[Filesystem] "Text file too busy" when trying to remove directories in a Vagrant shared folder #47804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
garethellis36 opened this issue Oct 6, 2022 · 8 comments

Comments

@garethellis36
Copy link

Symfony version(s) affected

5.4, 6.1

Description

I believe this issue was introduced by #40144, which made a change to doRemove to make copies of directories with temporary names before removing them.

I came across this while attempting to update dependencies in a legacy library which is a dependency of our main application.

When I run the tests for this legacy library, I get this:

> vendor/bin/phpunit
PHPUnit 9.5.25 #StandWithUkraine

Runtime:       PHP 8.1.11
Configuration: /var/other/flex/phpunit.xml

.....E......                                                      12 / 12 (100%)

Time: 00:00.095, Memory: 4.00 MB

There was 1 error:

1) IconLanguageServices\Flex\Test\Integration\FolderArchiverTest::test_it_can_move_files_to_archive_directory
IconLanguageServices\Flex\Exception\CouldNotArchive: Failed to archiveFailed to remove directory "/var/other/flex/test/Integration/TestFileSystem/src/..YzH": rmdir(/var/other/flex/test/Integration/TestFileSystem/src/..YzH): Text file busy

/var/other/flex/src/FolderArchiver.php:58
/var/other/flex/test/Integration/FolderArchiverTest.php:60

Caused by
Symfony\Component\Filesystem\Exception\IOException: Failed to remove directory "/var/other/flex/test/Integration/TestFileSystem/src/..YzH": rmdir(/var/other/flex/test/Integration/TestFileSystem/src/..YzH): Text file busy

/var/other/flex/vendor/symfony/filesystem/Filesystem.php:191
/var/other/flex/vendor/symfony/filesystem/Filesystem.php:150
/var/other/flex/src/FolderArchiver.php:56
/var/other/flex/test/Integration/FolderArchiverTest.php:60

ERRORS!
Tests: 12, Assertions: 15, Errors: 1.

The test which fails looks like this:

<?php

namespace IconLanguageServices\Flex\Test\Integration;

use IconLanguageServices\Flex\FolderArchiver;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;

class FolderArchiverTest extends \IconLanguageServices\Flex\Test\TestCase
{
    private Filesystem $fs;
    private string $src;
    private string $tgt;
    private FolderArchiver $archiver;

    public function setUp(): void
    {
        parent::setUp();
        $this->fs = new Filesystem();

        $this->src = __DIR__ . "/TestFileSystem/src/123";
        $this->tgt = __DIR__ . "/TestFileSystem/tgt";

        if (!$this->fs->exists($this->src)) {
            $this->fs->mkdir($this->src);
        }

        if (!$this->fs->exists("{$this->src}/file1")) {
            $this->fs->touch("{$this->src}/file1");
        }

        if (!$this->fs->exists("{$this->src}/file2")) {
            $this->fs->touch("{$this->src}/file2");
        }

        if (!$this->fs->exists($this->tgt)) {
            $this->fs->mkdir($this->tgt);
        }

        $this->archiver = new FolderArchiver($this->fs, new Finder(), $this->tgt);
    }

    public function tearDown(): void
    {
        parent::tearDown();
        if ($this->fs->exists($this->src)) {
            $this->fs->remove($this->src);
        }

        if ($this->fs->exists($this->tgt)) {
            $this->fs->remove($this->tgt);
        }
    }

    /**
     * @return void
     */
    public function test_it_can_move_files_to_archive_directory()
    {
        $this->archiver->archive($this->src);

        $this->assertFalse(
            file_exists($this->src),
            "Source folder has not been moved"
        );

        $date = date("Y-m-d");
        $this->assertTrue(
            file_exists($this->tgt . DIRECTORY_SEPARATOR . $date . DIRECTORY_SEPARATOR . "123"),
            "Folder named '123' not found in archive folder"
        );

        $this->assertTrue(
            file_exists($this->tgt . DIRECTORY_SEPARATOR . $date . DIRECTORY_SEPARATOR . "123" . DIRECTORY_SEPARATOR . "file1"),
            "File named 'file1' not found in archive sub-folder"
        );

        $this->assertTrue(
            file_exists($this->tgt . DIRECTORY_SEPARATOR . $date . DIRECTORY_SEPARATOR . "123" . DIRECTORY_SEPARATOR . "file2"),
            "File named 'file2' not found in archive sub-folder"
        );
    }
}

The subject-under-test looks like this:

<?php

namespace IconLanguageServices\Flex;

use IconLanguageServices\Flex\Exception\CouldNotArchive;
use IconLanguageServices\Flex\Exception\FolderNotFound;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;

class FolderArchiver
{
    /**
     * @var Filesystem
     */
    private $filesystem;

    /**
     * @var string
     */
    private $archiveFolder;
    /**
     * @var Finder
     */
    private $finder;

    public function __construct(Filesystem $filesystem, Finder $finder, $archiveFolder)
    {
        $this->filesystem = $filesystem;
        $this->finder = $finder;

        if (!$filesystem->exists($archiveFolder)) {
            $filesystem->mkdir($archiveFolder);
        }
        $this->archiveFolder = $archiveFolder;
    }

    /**
     * @param string $folder
     * @return void
     * @throws FolderNotFound
     */
    public function archive($folder)
    {
        if (!$this->filesystem->exists($folder)) {
            throw new FolderNotFound($folder . " not found");
        }
        
        try {
            foreach ($this->finder->files()->in($folder) as $file) {
                /** @var $file SplFileInfo */
                $this->filesystem->copy($file, $this->getArchiveDestination($folder) . $file->getFilename());
            }

            $this->filesystem->remove($folder);
        } catch (IOException $e) {
            throw new CouldNotArchive("Failed to archive" . $e->getMessage(), $e->getCode(), $e);
        }
    }

    /**
     * @param $folder
     * @return string
     */
    private function getArchiveDestination($folder)
    {
        $parts = array_filter(preg_split("/[\/\\\\]/", $folder));
        return $this->archiveFolder . DIRECTORY_SEPARATOR . date("Y-m-d") . DIRECTORY_SEPARATOR . array_pop($parts) . DIRECTORY_SEPARATOR;
    }
}

I am running PHP 8.1.1 inside a RHEL VM using Vagrant 2.3.0 and VirtualBox, with Windows 10 as the host OS. All files in the library's dir are shared from a directory in the host OS.

All tests passed in this same environment before I changed the dependency requirements.

I installed PHP 8.1 for Windows in the host OS and ran the tests in cmd.exe, and they all passed. The tests all pass in our CI environment (Jenkins on RHEL) as well. I am therefore confident that this is related to Vagrant.

How to reproduce

Run the PHPUnit test described above, for the SUT described above, on PHP 8.1 inside a Vagrant VM, with the files shared from a host OS.

Possible Solution

No response

Additional Context

No response

@domthomas-dev
Copy link

domthomas-dev commented Oct 14, 2022

Hi,

IMO, If issue is only inside Vagrant VM, maybe it's possible to use code like in isnfs function to check if we are inside a vagrant VM.
https://github.com/symfony/symfony/blob/6.2/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php#L197

Cc @nicolas-grekas in afup :)

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@garethellis36
Copy link
Author

garethellis36 commented May 4, 2023

Is this bug still relevant?

Yes

Have you managed to find a workaround?

No

@carsonbot carsonbot removed the Stalled label May 4, 2023
@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@garethellis36
Copy link
Author

Is this bug still relevant?

Yes

Have you managed to find a workaround?

No

@carsonbot carsonbot removed the Stalled label Nov 5, 2023
@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@garethellis36
Copy link
Author

Is this bug still relevant?

Yes

Have you managed to find a workaround?

No

@carsonbot carsonbot removed the Stalled label May 7, 2024
@garethellis36
Copy link
Author

We found a workaround. The tests I originally mentioned in this issue have been removed because the code was also removed, and for some other tests, we were able to configure development environment to use a directory that was in the guest OS filesystem, not the shared filesystem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants