From 844d5e3c463897aea1aa92a9a25dca51bbaa10cd Mon Sep 17 00:00:00 2001 From: Simon Asika Date: Thu, 9 May 2024 16:21:05 +0800 Subject: [PATCH] [Filesystem] Junstion detect an remove #1105 --- src/FileObject.php | 47 ++++++++++++++++++++++++++++++++++++++++++++++ src/Filesystem.php | 31 +++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/FileObject.php b/src/FileObject.php index 8838326..5321975 100644 --- a/src/FileObject.php +++ b/src/FileObject.php @@ -591,6 +591,10 @@ public function delete(): bool // In case of restricted permissions we zap it one way or the other // as long as the owner is either the webserver or the ftp try { + if ($this->isJunction()) { + return $this->removeJunction(); + } + if ($this->isDir()) { return rmdir($path); } @@ -794,6 +798,49 @@ public function isLink(): bool return $isLink; } + /** + * @see https://github.com/composer/composer/blob/4e5be9ee7d924d8efc58d676439b0c7bd18a9ce4/src/Composer/Util/Filesystem.php#L828 + * + * @return bool + */ + public function isJunction(): bool + { + if (!static::isWindows()) { + return false; + } + + $junction = $this->getPathname(); + + // Important to clear all caches first + clearstatcache(true, $junction); + + if (!is_dir($junction) || is_link($junction)) { + return false; + } + + $stat = lstat($junction); + + // S_ISDIR test (S_IFDIR is 0x4000, S_IFMT is 0xF000 bitmask) + return is_array($stat) && 0x4000 !== ($stat['mode'] & 0xF000); + } + + public function removeJunction(): bool + { + if (!static::isWindows()) { + return false; + } + + return rmdir($this->getPathname()); + } + + /** + * @return bool + */ + protected static function isWindows(): bool + { + return defined('PHP_WINDOWS_VERSION_BUILD'); + } + /** * @param string $name * @param array $args diff --git a/src/Filesystem.php b/src/Filesystem.php index a102aaa..548f46e 100644 --- a/src/Filesystem.php +++ b/src/Filesystem.php @@ -17,10 +17,10 @@ use Windwalker\Filesystem\Iterator\FilesIterator; use Windwalker\Promise\Promise; use Windwalker\Scalars\StringObject; -use Windwalker\Stream\Stream; use Windwalker\Utilities\Iterator\UniqueIterator; use Windwalker\Utilities\Str; +use function Windwalker\fs; use function Windwalker\uid; use const Windwalker\Stream\READ_ONLY_FROM_BEGIN; @@ -68,7 +68,7 @@ class Filesystem /** * Get a path as FileObject. * - * @param string $path + * @param string $path * @param string|null $root * * @return FileObject @@ -261,7 +261,7 @@ public static function createTempFolder( */ public static function symlink(string $target, string $link): bool { - $windows = defined('PHP_WINDOWS_VERSION_BUILD'); + $windows = static::isWindows(); $target = Path::normalize($target); $link = Path::normalize($link); @@ -281,6 +281,31 @@ public static function symlink(string $target, string $link): bool return symlink($target, $link); } + /** + * @return bool + */ + protected static function isWindows(): bool + { + return defined('PHP_WINDOWS_VERSION_BUILD'); + } + + public function isJunction(string $junction): bool + { + return fs($junction)->isJunction(); + } + + /** + * Removes a Windows NTFS junction. + * + * @param string $junction + * + * @return bool + */ + public function removeJunction(string $junction): bool + { + return fs($junction)->removeJunction(); + } + /** * __callStatic *