From e085a72f6450a83d173f0eaa7399158a7f5fd686 Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Thu, 31 Jan 2019 11:20:17 +0000 Subject: [PATCH 1/2] Fix mode bitmask when detecting a Windows junction --- src/Composer/Util/Filesystem.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index ebb7dfbd3..3a8f523fc 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -648,6 +648,10 @@ class Filesystem /** * Returns whether the target directory is a Windows NTFS Junction. * + * We test if the path is a directory and not an ordinary link, then check + * that the mode value returned from lstat (which gives the status of the + * link itself) is not a directory. + * * @param string $junction Path to check. * @return bool */ @@ -659,22 +663,14 @@ class Filesystem if (!is_dir($junction) || is_link($junction)) { return false; } - /** - * According to MSDN at https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx we can detect a junction now - * using the 'mode' value from stat: "The _S_IFDIR bit is set if path specifies a directory; the _S_IFREG bit - * is set if path specifies an ordinary file or a device." We have just tested for a directory above, so if - * we have a directory that isn't one according to lstat(...) we must have a junction. - * - * #define _S_IFDIR 0x4000 - * #define _S_IFREG 0x8000 - * - * Stat cache should be cleared before to avoid accidentally reading wrong information from previous installs. - */ + + // Important to clear cache first clearstatcache(true, $junction); clearstatcache(false); $stat = lstat($junction); - return !($stat['mode'] & 0xC000); + // S_IFDIR is 0x4000, S_IFMT is the 0xF000 bitmask + return $stat ? 0x4000 !== ($stat['mode'] & 0xF000) : false; } /** From da0dc74414fd8e6eca65619a6d9c1dd1a04facc6 Mon Sep 17 00:00:00 2001 From: johnstevenson Date: Sun, 10 Feb 2019 14:41:20 +0000 Subject: [PATCH 2/2] Update doc block, remove redundant clearstatcache --- src/Composer/Util/Filesystem.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 3a8f523fc..2ebc434b7 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -652,6 +652,11 @@ class Filesystem * that the mode value returned from lstat (which gives the status of the * link itself) is not a directory. * + * This relies on the fact that PHP does not set this value because there is + * no universal file type flag for a junction or a mount point. However a + * bug in PHP can cause a random value to be returned and this could result + * in a junction not being detected: https://bugs.php.net/bug.php?id=77552 + * * @param string $junction Path to check. * @return bool */ @@ -664,9 +669,8 @@ class Filesystem return false; } - // Important to clear cache first + // Important to clear all caches first clearstatcache(true, $junction); - clearstatcache(false); $stat = lstat($junction); // S_IFDIR is 0x4000, S_IFMT is the 0xF000 bitmask