protected function mirrorDir()
    {
        if (!$this->useTmpDir) {
            $this->tmpDir = $this->dir;
            return;
        }
        $this->tmpDir = md5(time());
        if (file_exists($this->tmpDir)) {
            $this->fs->remove($this->tmpDir);
        }
        $this->printTaskInfo(sprintf(
            'Creating temporary directory %s.',
            $this->tmpDir
        ));
        $this->fs->mkdir($this->tmpDir);
        $tmpRealPath = realpath($this->tmpDir);

        $directoryIterator = new \RecursiveDirectoryIterator($this->dir, \RecursiveDirectoryIterator::SKIP_DOTS);
        $recursiveIterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
        $filterIterator = new \CallbackFilterIterator(
            $recursiveIterator,
            function ($current) use ($tmpRealPath) {
                return strpos($current->getRealPath(), $tmpRealPath) !== 0;
            }
        );
        $this->printTaskInfo(sprintf(
            'Mirroring directory %s to temporary directory %s.',
            $this->dir,
            $tmpRealPath
        ));
        foreach ($filterIterator as $item) {
            if (strpos($item->getRealPath(), $tmpRealPath) === 0) {
                continue;
            }
            if (is_link($item)) {
                if ($item->getRealPath() !== false) {
                    $this->fs->symlink(
                        $item->getLinkTarget(),
                        $this->tmpDir . DIRECTORY_SEPARATOR . $filterIterator->getSubPathName()
                    );
                }
                continue;
            }
            if ($item->isDir()) {
                $this->fs->mkdir($this->tmpDir . DIRECTORY_SEPARATOR . $filterIterator->getSubPathName());
                continue;
            }
            $this->fs->copy($item, $this->tmpDir . DIRECTORY_SEPARATOR . $filterIterator->getSubPathName());
        }
    }