Introduce a cross-platform safe version of is_readable to support UNC / wsl$ paths on Windows (#9861)

main
Jordi Boggiano 3 years ago committed by GitHub
parent bfea0f7d1e
commit 3380178798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -346,7 +346,7 @@ EOF;
$classmapFile .= ");\n";
if (!$suffix) {
if (!$config->get('autoloader-suffix') && is_readable($vendorPath.'/autoload.php')) {
if (!$config->get('autoloader-suffix') && Filesystem::isReadable($vendorPath.'/autoload.php')) {
$content = file_get_contents($vendorPath.'/autoload.php');
if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
$suffix = $match[1];
@ -1131,7 +1131,7 @@ INITIALIZER;
foreach ($autoload[$type] as $namespace => $paths) {
foreach ((array) $paths as $path) {
if (($type === 'files' || $type === 'classmap' || $type === 'exclude-from-classmap') && $package->getTargetDir() && !is_readable($installPath.'/'.$path)) {
if (($type === 'files' || $type === 'classmap' || $type === 'exclude-from-classmap') && $package->getTargetDir() && !Filesystem::isReadable($installPath.'/'.$path)) {
// remove target-dir from file paths of the root package
if ($package === $rootPackage) {
$targetDir = str_replace('\\<dirsep\\>', '[\\\\/]', preg_quote(str_replace(array('/', '\\'), '<dirsep>', $package->getTargetDir())));

@ -225,7 +225,7 @@ class ClassMapGenerator
if (!$contents) {
if (!file_exists($path)) {
$message = 'File at "%s" does not exist, check your classmap definitions';
} elseif (!is_readable($path)) {
} elseif (!Filesystem::isReadable($path)) {
$message = 'File at "%s" is not readable, check its permissions';
} elseif ('' === trim(file_get_contents($path))) {
// The input file was really empty and thus contains no classes

@ -12,6 +12,7 @@
namespace Composer\Command;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
use Composer\Util\Silencer;
use Symfony\Component\Console\Input\InputInterface;
@ -411,7 +412,7 @@ EOT
'secure-http' => array($booleanValidator, $booleanNormalizer),
'cafile' => array(
function ($val) {
return file_exists($val) && is_readable($val);
return file_exists($val) && Filesystem::isReadable($val);
},
function ($val) {
return $val === 'null' ? null : $val;
@ -419,7 +420,7 @@ EOT
),
'capath' => array(
function ($val) {
return is_dir($val) && is_readable($val);
return is_dir($val) && Filesystem::isReadable($val);
},
function ($val) {
return $val === 'null' ? null : $val;

@ -796,7 +796,7 @@ EOT
}
$file = Factory::getComposerFile();
if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
if (is_file($file) && Filesystem::isReadable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
if (!empty($composer['minimum-stability'])) {
return VersionParser::normalizeStability($composer['minimum-stability']);
}

@ -13,6 +13,7 @@
namespace Composer\Command;
use Composer\DependencyResolver\Request;
use Composer\Util\Filesystem;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
@ -119,9 +120,7 @@ EOT
return 1;
}
// check for readability by reading the file as is_readable can not be trusted on network-mounts
// see https://github.com/composer/composer/issues/8231 and https://bugs.php.net/bug.php?id=68926
if (!is_readable($this->file) && false === Silencer::call('file_get_contents', $this->file)) {
if (!Filesystem::isReadable($this->file)) {
$io->writeError('<error>'.$this->file.' is not readable.</error>');
return 1;

@ -381,7 +381,7 @@ TAGSPUBKEY
if (!is_file($oldFile)) {
throw new FilesystemException('Composer rollback failed: "'.$oldFile.'" could not be found');
}
if (!is_readable($oldFile)) {
if (!Filesystem::isReadable($oldFile)) {
throw new FilesystemException('Composer rollback failed: "'.$oldFile.'" could not be read');
}
@ -582,7 +582,7 @@ EOT;
@unlink($script);
// see if the file was moved and is still accessible
if ($result = is_readable($localFilename) && (hash_file('sha256', $localFilename) === $checksum)) {
if ($result = Filesystem::isReadable($localFilename) && (hash_file('sha256', $localFilename) === $checksum)) {
$io->writeError('<info>Operation succeeded.</info>');
@unlink($newFilename);
} else {

@ -17,6 +17,7 @@ use Composer\Package\Loader\ValidatingArrayLoader;
use Composer\Plugin\CommandEvent;
use Composer\Plugin\PluginEvents;
use Composer\Util\ConfigValidator;
use Composer\Util\Filesystem;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -77,7 +78,7 @@ EOT
return 3;
}
if (!is_readable($file)) {
if (!Filesystem::isReadable($file)) {
$io->writeError('<error>' . $file . ' is not readable.</error>');
return 3;

@ -15,6 +15,7 @@ namespace Composer\Config;
use Composer\Json\JsonFile;
use Composer\Json\JsonManipulator;
use Composer\Json\JsonValidationException;
use Composer\Util\Filesystem;
use Composer\Util\Silencer;
/**
@ -217,7 +218,7 @@ class JsonConfigSource implements ConfigSourceInterface
throw new \RuntimeException(sprintf('The file "%s" is not writable.', $this->file->getPath()));
}
if (!is_readable($this->file->getPath())) {
if (!Filesystem::isReadable($this->file->getPath())) {
throw new \RuntimeException(sprintf('The file "%s" is not readable.', $this->file->getPath()));
}

@ -13,6 +13,7 @@
namespace Composer\Console;
use Composer\IO\NullIO;
use Composer\Util\Filesystem;
use Composer\Util\Platform;
use Composer\Util\Silencer;
use Symfony\Component\Console\Application as BaseApplication;
@ -282,7 +283,7 @@ class Application extends BaseApplication
// add non-standard scripts as own commands
$file = Factory::getComposerFile();
if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
if (is_file($file) && Filesystem::isReadable($file) && is_array($composer = json_decode(file_get_contents($file), true))) {
if (isset($composer['scripts']) && is_array($composer['scripts'])) {
foreach ($composer['scripts'] as $script => $dummy) {
if (!defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {

@ -79,7 +79,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$installPath = $this->getInstallPath($package);
if (is_readable($installPath)) {
if (Filesystem::isReadable($installPath)) {
return true;
}
@ -128,7 +128,7 @@ class LibraryInstaller implements InstallerInterface, BinaryPresenceInterface
$downloadPath = $this->getInstallPath($package);
// remove the binaries if it appears the package files are missing
if (!is_readable($downloadPath) && $repo->hasPackage($package)) {
if (!Filesystem::isReadable($downloadPath) && $repo->hasPackage($package)) {
$this->binaryInstaller->removeBinaries($package);
}

@ -600,6 +600,33 @@ class Filesystem
return preg_replace('{^file://}i', '', $path);
}
/**
* Cross-platform safe version of is_readable()
*
* This will also check for readability by reading the file as is_readable can not be trusted on network-mounts
* and \\wsl$ paths. See https://github.com/composer/composer/issues/8231 and https://bugs.php.net/bug.php?id=68926
*
* @param string $path
* @return bool
*/
public static function isReadable($path)
{
if (is_readable($path)) {
return true;
}
if (is_file($path)) {
return false !== Silencer::call('file_get_contents', $path, false, null, 0, 1);
}
if (is_dir($path)) {
return false !== Silencer::call('opendir', $path);
}
// assume false otherwise
return false;
}
protected function directorySize($directory)
{
$it = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::SKIP_DOTS);

@ -211,11 +211,11 @@ final class StreamContextFactory
}
}
if (isset($defaults['ssl']['cafile']) && (!is_readable($defaults['ssl']['cafile']) || !CaBundle::validateCaFile($defaults['ssl']['cafile'], $logger))) {
if (isset($defaults['ssl']['cafile']) && (!Filesystem::isReadable($defaults['ssl']['cafile']) || !CaBundle::validateCaFile($defaults['ssl']['cafile'], $logger))) {
throw new TransportException('The configured cafile was not valid or could not be read.');
}
if (isset($defaults['ssl']['capath']) && (!is_dir($defaults['ssl']['capath']) || !is_readable($defaults['ssl']['capath']))) {
if (isset($defaults['ssl']['capath']) && (!is_dir($defaults['ssl']['capath']) || !Filesystem::isReadable($defaults['ssl']['capath']))) {
throw new TransportException('The configured capath was not valid or could not be read.');
}

Loading…
Cancel
Save