diff --git a/apps/files_external/3rdparty/.gitignore b/apps/files_external/3rdparty/.gitignore index 5eae814c79..651eb60572 100644 --- a/apps/files_external/3rdparty/.gitignore +++ b/apps/files_external/3rdparty/.gitignore @@ -6,3 +6,6 @@ icewind/smb/Makefile icewind/smb/.travis.yml icewind/smb/.scrutinizer.yml icewind/streams/tests +.github +.php_cs* +psalm.xml diff --git a/apps/files_external/3rdparty/composer.json b/apps/files_external/3rdparty/composer.json index f38f175dd6..3f237c827e 100644 --- a/apps/files_external/3rdparty/composer.json +++ b/apps/files_external/3rdparty/composer.json @@ -8,7 +8,7 @@ "classmap-authoritative": true }, "require": { - "icewind/streams": "0.7.1", - "icewind/smb": "3.2.7" + "icewind/streams": "0.7.3", + "icewind/smb": "3.4.0" } } diff --git a/apps/files_external/3rdparty/composer.lock b/apps/files_external/3rdparty/composer.lock index de8642d82f..7e180c3366 100644 --- a/apps/files_external/3rdparty/composer.lock +++ b/apps/files_external/3rdparty/composer.lock @@ -4,29 +4,31 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6181c23a5c03b00fbdc659d87c1ad67d", + "content-hash": "9905ed45527f669a4165a8b83b6e4141", "packages": [ { "name": "icewind/smb", - "version": "v3.2.7", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/icewind1991/SMB.git", - "reference": "743a7bf35317f1b76cf8e8b804e54a6c5faacad6" + "reference": "b5c6921f2e91229c9f71556a4713b4fac91fd394" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/icewind1991/SMB/zipball/743a7bf35317f1b76cf8e8b804e54a6c5faacad6", - "reference": "743a7bf35317f1b76cf8e8b804e54a6c5faacad6", + "url": "https://api.github.com/repos/icewind1991/SMB/zipball/b5c6921f2e91229c9f71556a4713b4fac91fd394", + "reference": "b5c6921f2e91229c9f71556a4713b4fac91fd394", "shasum": "" }, "require": { - "icewind/streams": ">=0.2.0", - "php": ">=7.1" + "icewind/streams": ">=0.7.3", + "php": ">=7.2" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.13", - "phpunit/phpunit": "^7.0" + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.57", + "phpunit/phpunit": "^8.5|^9.3.8", + "psalm/phar": "^4.3" }, "type": "library", "autoload": { @@ -45,33 +47,37 @@ } ], "description": "php wrapper for smbclient and libsmbclient-php", - "time": "2020-09-03T13:00:22+00:00" + "support": { + "issues": "https://github.com/icewind1991/SMB/issues", + "source": "https://github.com/icewind1991/SMB/tree/v3.4.0" + }, + "time": "2021-03-10T14:00:37+00:00" }, { "name": "icewind/streams", - "version": "v0.7.1", + "version": "v0.7.3", "source": { "type": "git", "url": "https://github.com/icewind1991/Streams.git", - "reference": "4db3ed6c366e90b958d00e1d4c6360a9b39b2121" + "reference": "22ef9fc5b50d645dbc202206a656cc4dde28f95c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/icewind1991/Streams/zipball/4db3ed6c366e90b958d00e1d4c6360a9b39b2121", - "reference": "4db3ed6c366e90b958d00e1d4c6360a9b39b2121", + "url": "https://api.github.com/repos/icewind1991/Streams/zipball/22ef9fc5b50d645dbc202206a656cc4dde28f95c", + "reference": "22ef9fc5b50d645dbc202206a656cc4dde28f95c", "shasum": "" }, "require": { - "php": ">=5.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8", - "satooshi/php-coveralls": "v1.0.0" + "friendsofphp/php-cs-fixer": "^2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^9" }, "type": "library", "autoload": { "psr-4": { - "Icewind\\Streams\\Tests\\": "tests/", "Icewind\\Streams\\": "src/" } }, @@ -86,7 +92,11 @@ } ], "description": "A set of generic stream wrappers", - "time": "2019-02-15T12:57:29+00:00" + "support": { + "issues": "https://github.com/icewind1991/Streams/issues", + "source": "https://github.com/icewind1991/Streams/tree/v0.7.3" + }, + "time": "2021-03-02T19:33:35+00:00" } ], "packages-dev": [], @@ -97,5 +107,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.0.0" } diff --git a/apps/files_external/3rdparty/composer/ClassLoader.php b/apps/files_external/3rdparty/composer/ClassLoader.php index fce8549f07..247294d66e 100644 --- a/apps/files_external/3rdparty/composer/ClassLoader.php +++ b/apps/files_external/3rdparty/composer/ClassLoader.php @@ -37,11 +37,13 @@ namespace Composer\Autoload; * * @author Fabien Potencier * @author Jordi Boggiano - * @see http://www.php-fig.org/psr/psr-0/ - * @see http://www.php-fig.org/psr/psr-4/ + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ */ class ClassLoader { + private $vendorDir; + // PSR-4 private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); @@ -57,10 +59,17 @@ class ClassLoader private $missingClasses = array(); private $apcuPrefix; + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + public function getPrefixes() { if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); } return array(); @@ -300,6 +309,17 @@ class ClassLoader public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } } /** @@ -308,6 +328,10 @@ class ClassLoader public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } } /** @@ -367,6 +391,16 @@ class ClassLoader return $file; } + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + private function findFileWithExtension($class, $ext) { // PSR-4 lookup diff --git a/apps/files_external/3rdparty/composer/InstalledVersions.php b/apps/files_external/3rdparty/composer/InstalledVersions.php new file mode 100644 index 0000000000..71cd811ef8 --- /dev/null +++ b/apps/files_external/3rdparty/composer/InstalledVersions.php @@ -0,0 +1,301 @@ + + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '62929cc646134fbd409cfb4eacb7039d15763b96', + 'name' => 'files_external/3rdparty', + ), + 'versions' => + array ( + 'files_external/3rdparty' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '62929cc646134fbd409cfb4eacb7039d15763b96', + ), + 'icewind/smb' => + array ( + 'pretty_version' => 'v3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'b5c6921f2e91229c9f71556a4713b4fac91fd394', + ), + 'icewind/streams' => + array ( + 'pretty_version' => 'v0.7.3', + 'version' => '0.7.3.0', + 'aliases' => + array ( + ), + 'reference' => '22ef9fc5b50d645dbc202206a656cc4dde28f95c', + ), + ), +); +private static $canGetVendors; +private static $installedByVendor = array(); + + + + + + + +public static function getInstalledPackages() +{ +$packages = array(); +foreach (self::getInstalled() as $installed) { +$packages[] = array_keys($installed['versions']); +} + + +if (1 === \count($packages)) { +return $packages[0]; +} + +return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); +} + + + + + + + + + +public static function isInstalled($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (isset($installed['versions'][$packageName])) { +return true; +} +} + +return false; +} + + + + + + + + + + + + + + +public static function satisfies(VersionParser $parser, $packageName, $constraint) +{ +$constraint = $parser->parseConstraints($constraint); +$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + +return $provided->matches($constraint); +} + + + + + + + + + + +public static function getVersionRanges($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +$ranges = array(); +if (isset($installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = $installed['versions'][$packageName]['pretty_version']; +} +if (array_key_exists('aliases', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); +} +if (array_key_exists('replaced', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); +} +if (array_key_exists('provided', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); +} + +return implode(' || ', $ranges); +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['version'])) { +return null; +} + +return $installed['versions'][$packageName]['version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getPrettyVersion($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['pretty_version'])) { +return null; +} + +return $installed['versions'][$packageName]['pretty_version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getReference($packageName) +{ +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; +} + +if (!isset($installed['versions'][$packageName]['reference'])) { +return null; +} + +return $installed['versions'][$packageName]['reference']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + + + + + +public static function getRootPackage() +{ +$installed = self::getInstalled(); + +return $installed[0]['root']; +} + + + + + + + +public static function getRawData() +{ +return self::$installed; +} + + + + + + + + + + + + + + + + + + + +public static function reload($data) +{ +self::$installed = $data; +self::$installedByVendor = array(); +} + + + + +private static function getInstalled() +{ +if (null === self::$canGetVendors) { +self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); +} + +$installed = array(); + +if (self::$canGetVendors) { +foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { +if (isset(self::$installedByVendor[$vendorDir])) { +$installed[] = self::$installedByVendor[$vendorDir]; +} elseif (is_file($vendorDir.'/composer/installed.php')) { +$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; +} +} +} + +$installed[] = self::$installed; + +return $installed; +} +} diff --git a/apps/files_external/3rdparty/composer/autoload_classmap.php b/apps/files_external/3rdparty/composer/autoload_classmap.php index a563765eb9..d0f82994f2 100644 --- a/apps/files_external/3rdparty/composer/autoload_classmap.php +++ b/apps/files_external/3rdparty/composer/autoload_classmap.php @@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = $vendorDir; return array( + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'Icewind\\SMB\\ACL' => $vendorDir . '/icewind/smb/src/ACL.php', 'Icewind\\SMB\\AbstractServer' => $vendorDir . '/icewind/smb/src/AbstractServer.php', 'Icewind\\SMB\\AbstractShare' => $vendorDir . '/icewind/smb/src/AbstractShare.php', @@ -57,6 +58,7 @@ return array( 'Icewind\\SMB\\Native\\NativeWriteStream' => $vendorDir . '/icewind/smb/src/Native/NativeWriteStream.php', 'Icewind\\SMB\\Options' => $vendorDir . '/icewind/smb/src/Options.php', 'Icewind\\SMB\\ServerFactory' => $vendorDir . '/icewind/smb/src/ServerFactory.php', + 'Icewind\\SMB\\StringBuffer' => $vendorDir . '/icewind/smb/src/StringBuffer.php', 'Icewind\\SMB\\System' => $vendorDir . '/icewind/smb/src/System.php', 'Icewind\\SMB\\TimeZoneProvider' => $vendorDir . '/icewind/smb/src/TimeZoneProvider.php', 'Icewind\\SMB\\Wrapped\\Connection' => $vendorDir . '/icewind/smb/src/Wrapped/Connection.php', @@ -73,13 +75,17 @@ return array( 'Icewind\\Streams\\DirectoryFilter' => $vendorDir . '/icewind/streams/src/DirectoryFilter.php', 'Icewind\\Streams\\DirectoryWrapper' => $vendorDir . '/icewind/streams/src/DirectoryWrapper.php', 'Icewind\\Streams\\File' => $vendorDir . '/icewind/streams/src/File.php', + 'Icewind\\Streams\\HashWrapper' => $vendorDir . '/icewind/streams/src/HashWrapper.php', 'Icewind\\Streams\\IteratorDirectory' => $vendorDir . '/icewind/streams/src/IteratorDirectory.php', 'Icewind\\Streams\\NullWrapper' => $vendorDir . '/icewind/streams/src/NullWrapper.php', 'Icewind\\Streams\\Path' => $vendorDir . '/icewind/streams/src/Path.php', 'Icewind\\Streams\\PathWrapper' => $vendorDir . '/icewind/streams/src/PathWrapper.php', + 'Icewind\\Streams\\ReadHashWrapper' => $vendorDir . '/icewind/streams/src/ReadHashWrapper.php', 'Icewind\\Streams\\RetryWrapper' => $vendorDir . '/icewind/streams/src/RetryWrapper.php', 'Icewind\\Streams\\SeekableWrapper' => $vendorDir . '/icewind/streams/src/SeekableWrapper.php', 'Icewind\\Streams\\Url' => $vendorDir . '/icewind/streams/src/Url.php', - 'Icewind\\Streams\\UrlCallback' => $vendorDir . '/icewind/streams/src/UrlCallBack.php', + 'Icewind\\Streams\\UrlCallback' => $vendorDir . '/icewind/streams/src/UrlCallback.php', 'Icewind\\Streams\\Wrapper' => $vendorDir . '/icewind/streams/src/Wrapper.php', + 'Icewind\\Streams\\WrapperHandler' => $vendorDir . '/icewind/streams/src/WrapperHandler.php', + 'Icewind\\Streams\\WriteHashWrapper' => $vendorDir . '/icewind/streams/src/WriteHashWrapper.php', ); diff --git a/apps/files_external/3rdparty/composer/autoload_psr4.php b/apps/files_external/3rdparty/composer/autoload_psr4.php index 82614b5016..e34149b31a 100644 --- a/apps/files_external/3rdparty/composer/autoload_psr4.php +++ b/apps/files_external/3rdparty/composer/autoload_psr4.php @@ -6,7 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = $vendorDir; return array( - 'Icewind\\Streams\\Tests\\' => array($vendorDir . '/icewind/streams/tests'), 'Icewind\\Streams\\' => array($vendorDir . '/icewind/streams/src'), 'Icewind\\SMB\\' => array($vendorDir . '/icewind/smb/src'), ); diff --git a/apps/files_external/3rdparty/composer/autoload_real.php b/apps/files_external/3rdparty/composer/autoload_real.php index 36857d406c..7ff3e29252 100644 --- a/apps/files_external/3rdparty/composer/autoload_real.php +++ b/apps/files_external/3rdparty/composer/autoload_real.php @@ -22,13 +22,15 @@ class ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3 return self::$loader; } + require __DIR__ . '/platform_check.php'; + spl_autoload_register(array('ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { - require_once __DIR__ . '/autoload_static.php'; + require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3::getInitializer($loader)); } else { diff --git a/apps/files_external/3rdparty/composer/autoload_static.php b/apps/files_external/3rdparty/composer/autoload_static.php index 7ae9c4fff7..899982f2a6 100644 --- a/apps/files_external/3rdparty/composer/autoload_static.php +++ b/apps/files_external/3rdparty/composer/autoload_static.php @@ -9,17 +9,12 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3 public static $prefixLengthsPsr4 = array ( 'I' => array ( - 'Icewind\\Streams\\Tests\\' => 22, 'Icewind\\Streams\\' => 16, 'Icewind\\SMB\\' => 12, ), ); public static $prefixDirsPsr4 = array ( - 'Icewind\\Streams\\Tests\\' => - array ( - 0 => __DIR__ . '/..' . '/icewind/streams/tests', - ), 'Icewind\\Streams\\' => array ( 0 => __DIR__ . '/..' . '/icewind/streams/src', @@ -31,6 +26,7 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3 ); public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'Icewind\\SMB\\ACL' => __DIR__ . '/..' . '/icewind/smb/src/ACL.php', 'Icewind\\SMB\\AbstractServer' => __DIR__ . '/..' . '/icewind/smb/src/AbstractServer.php', 'Icewind\\SMB\\AbstractShare' => __DIR__ . '/..' . '/icewind/smb/src/AbstractShare.php', @@ -82,6 +78,7 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3 'Icewind\\SMB\\Native\\NativeWriteStream' => __DIR__ . '/..' . '/icewind/smb/src/Native/NativeWriteStream.php', 'Icewind\\SMB\\Options' => __DIR__ . '/..' . '/icewind/smb/src/Options.php', 'Icewind\\SMB\\ServerFactory' => __DIR__ . '/..' . '/icewind/smb/src/ServerFactory.php', + 'Icewind\\SMB\\StringBuffer' => __DIR__ . '/..' . '/icewind/smb/src/StringBuffer.php', 'Icewind\\SMB\\System' => __DIR__ . '/..' . '/icewind/smb/src/System.php', 'Icewind\\SMB\\TimeZoneProvider' => __DIR__ . '/..' . '/icewind/smb/src/TimeZoneProvider.php', 'Icewind\\SMB\\Wrapped\\Connection' => __DIR__ . '/..' . '/icewind/smb/src/Wrapped/Connection.php', @@ -98,15 +95,19 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3 'Icewind\\Streams\\DirectoryFilter' => __DIR__ . '/..' . '/icewind/streams/src/DirectoryFilter.php', 'Icewind\\Streams\\DirectoryWrapper' => __DIR__ . '/..' . '/icewind/streams/src/DirectoryWrapper.php', 'Icewind\\Streams\\File' => __DIR__ . '/..' . '/icewind/streams/src/File.php', + 'Icewind\\Streams\\HashWrapper' => __DIR__ . '/..' . '/icewind/streams/src/HashWrapper.php', 'Icewind\\Streams\\IteratorDirectory' => __DIR__ . '/..' . '/icewind/streams/src/IteratorDirectory.php', 'Icewind\\Streams\\NullWrapper' => __DIR__ . '/..' . '/icewind/streams/src/NullWrapper.php', 'Icewind\\Streams\\Path' => __DIR__ . '/..' . '/icewind/streams/src/Path.php', 'Icewind\\Streams\\PathWrapper' => __DIR__ . '/..' . '/icewind/streams/src/PathWrapper.php', + 'Icewind\\Streams\\ReadHashWrapper' => __DIR__ . '/..' . '/icewind/streams/src/ReadHashWrapper.php', 'Icewind\\Streams\\RetryWrapper' => __DIR__ . '/..' . '/icewind/streams/src/RetryWrapper.php', 'Icewind\\Streams\\SeekableWrapper' => __DIR__ . '/..' . '/icewind/streams/src/SeekableWrapper.php', 'Icewind\\Streams\\Url' => __DIR__ . '/..' . '/icewind/streams/src/Url.php', - 'Icewind\\Streams\\UrlCallback' => __DIR__ . '/..' . '/icewind/streams/src/UrlCallBack.php', + 'Icewind\\Streams\\UrlCallback' => __DIR__ . '/..' . '/icewind/streams/src/UrlCallback.php', 'Icewind\\Streams\\Wrapper' => __DIR__ . '/..' . '/icewind/streams/src/Wrapper.php', + 'Icewind\\Streams\\WrapperHandler' => __DIR__ . '/..' . '/icewind/streams/src/WrapperHandler.php', + 'Icewind\\Streams\\WriteHashWrapper' => __DIR__ . '/..' . '/icewind/streams/src/WriteHashWrapper.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/apps/files_external/3rdparty/composer/installed.json b/apps/files_external/3rdparty/composer/installed.json index d903f99b5d..e6950959c4 100644 --- a/apps/files_external/3rdparty/composer/installed.json +++ b/apps/files_external/3rdparty/composer/installed.json @@ -1,88 +1,104 @@ -[ - { - "name": "icewind/smb", - "version": "v3.2.7", - "version_normalized": "3.2.7.0", - "source": { - "type": "git", - "url": "https://github.com/icewind1991/SMB.git", - "reference": "743a7bf35317f1b76cf8e8b804e54a6c5faacad6" +{ + "packages": [ + { + "name": "icewind/smb", + "version": "v3.4.0", + "version_normalized": "3.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/icewind1991/SMB.git", + "reference": "b5c6921f2e91229c9f71556a4713b4fac91fd394" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/icewind1991/SMB/zipball/b5c6921f2e91229c9f71556a4713b4fac91fd394", + "reference": "b5c6921f2e91229c9f71556a4713b4fac91fd394", + "shasum": "" + }, + "require": { + "icewind/streams": ">=0.7.3", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.57", + "phpunit/phpunit": "^8.5|^9.3.8", + "psalm/phar": "^4.3" + }, + "time": "2021-03-10T14:00:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Icewind\\SMB\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Robin Appelman", + "email": "icewind@owncloud.com" + } + ], + "description": "php wrapper for smbclient and libsmbclient-php", + "support": { + "issues": "https://github.com/icewind1991/SMB/issues", + "source": "https://github.com/icewind1991/SMB/tree/v3.4.0" + }, + "install-path": "../icewind/smb" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/icewind1991/SMB/zipball/743a7bf35317f1b76cf8e8b804e54a6c5faacad6", - "reference": "743a7bf35317f1b76cf8e8b804e54a6c5faacad6", - "shasum": "" - }, - "require": { - "icewind/streams": ">=0.2.0", - "php": ">=7.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.13", - "phpunit/phpunit": "^7.0" - }, - "time": "2020-09-03T13:00:22+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Icewind\\SMB\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Robin Appelman", - "email": "icewind@owncloud.com" - } - ], - "description": "php wrapper for smbclient and libsmbclient-php" - }, - { - "name": "icewind/streams", - "version": "v0.7.1", - "version_normalized": "0.7.1.0", - "source": { - "type": "git", - "url": "https://github.com/icewind1991/Streams.git", - "reference": "4db3ed6c366e90b958d00e1d4c6360a9b39b2121" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/icewind1991/Streams/zipball/4db3ed6c366e90b958d00e1d4c6360a9b39b2121", - "reference": "4db3ed6c366e90b958d00e1d4c6360a9b39b2121", - "shasum": "" - }, - "require": { - "php": ">=5.3" - }, - "require-dev": { - "phpunit/phpunit": "^4.8", - "satooshi/php-coveralls": "v1.0.0" - }, - "time": "2019-02-15T12:57:29+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Icewind\\Streams\\Tests\\": "tests/", - "Icewind\\Streams\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Robin Appelman", - "email": "icewind@owncloud.com" - } - ], - "description": "A set of generic stream wrappers" - } -] + { + "name": "icewind/streams", + "version": "v0.7.3", + "version_normalized": "0.7.3.0", + "source": { + "type": "git", + "url": "https://github.com/icewind1991/Streams.git", + "reference": "22ef9fc5b50d645dbc202206a656cc4dde28f95c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/icewind1991/Streams/zipball/22ef9fc5b50d645dbc202206a656cc4dde28f95c", + "reference": "22ef9fc5b50d645dbc202206a656cc4dde28f95c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^9" + }, + "time": "2021-03-02T19:33:35+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Icewind\\Streams\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Robin Appelman", + "email": "icewind@owncloud.com" + } + ], + "description": "A set of generic stream wrappers", + "support": { + "issues": "https://github.com/icewind1991/Streams/issues", + "source": "https://github.com/icewind1991/Streams/tree/v0.7.3" + }, + "install-path": "../icewind/streams" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/apps/files_external/3rdparty/composer/installed.php b/apps/files_external/3rdparty/composer/installed.php new file mode 100644 index 0000000000..8d83406926 --- /dev/null +++ b/apps/files_external/3rdparty/composer/installed.php @@ -0,0 +1,42 @@ + + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '62929cc646134fbd409cfb4eacb7039d15763b96', + 'name' => 'files_external/3rdparty', + ), + 'versions' => + array ( + 'files_external/3rdparty' => + array ( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'aliases' => + array ( + ), + 'reference' => '62929cc646134fbd409cfb4eacb7039d15763b96', + ), + 'icewind/smb' => + array ( + 'pretty_version' => 'v3.4.0', + 'version' => '3.4.0.0', + 'aliases' => + array ( + ), + 'reference' => 'b5c6921f2e91229c9f71556a4713b4fac91fd394', + ), + 'icewind/streams' => + array ( + 'pretty_version' => 'v0.7.3', + 'version' => '0.7.3.0', + 'aliases' => + array ( + ), + 'reference' => '22ef9fc5b50d645dbc202206a656cc4dde28f95c', + ), + ), +); diff --git a/apps/files_external/3rdparty/composer/platform_check.php b/apps/files_external/3rdparty/composer/platform_check.php new file mode 100644 index 0000000000..589e9e770b --- /dev/null +++ b/apps/files_external/3rdparty/composer/platform_check.php @@ -0,0 +1,26 @@ += 70200)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/apps/files_external/3rdparty/icewind/smb/.gitignore b/apps/files_external/3rdparty/icewind/smb/.gitignore index 17e19f04f5..ff449e1b5d 100644 --- a/apps/files_external/3rdparty/icewind/smb/.gitignore +++ b/apps/files_external/3rdparty/icewind/smb/.gitignore @@ -4,3 +4,4 @@ composer.lock .php_cs.cache listen.php test.php +*.cache \ No newline at end of file diff --git a/apps/files_external/3rdparty/icewind/smb/README.md b/apps/files_external/3rdparty/icewind/smb/README.md index 6a35e736ac..272c4ebedc 100644 --- a/apps/files_external/3rdparty/icewind/smb/README.md +++ b/apps/files_external/3rdparty/icewind/smb/README.md @@ -1,9 +1,8 @@ SMB === -[![Code Coverage](https://scrutinizer-ci.com/g/icewind1991/SMB/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/icewind1991/SMB/?branch=master) -[![Build Status](https://travis-ci.org/icewind1991/SMB.svg?branch=master)](https://travis-ci.org/icewind1991/SMB) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/icewind1991/SMB/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/icewind1991/SMB/?branch=master) +[![CI](https://github.com/icewind1991/SMB/actions/workflows/ci.yaml/badge.svg)](https://github.com/icewind1991/SMB/actions/workflows/ci.yaml) +[![codecov](https://codecov.io/gh/icewind1991/SMB/branch/master/graph/badge.svg?token=eTg0P466k6)](https://codecov.io/gh/icewind1991/SMB) PHP wrapper for `smbclient` and [`libsmbclient-php`](https://github.com/eduardok/libsmbclient-php) @@ -103,7 +102,7 @@ fclose($fh); ``` **Note**: write() will truncate your file to 0bytes. You may open a writeable stream with append() which will point -the cursor to the end of the file or create it if it does not exists yet. (append() is only compatible with libsmbclient-php) +the cursor to the end of the file or create it if it does not exist yet. (append() is only compatible with libsmbclient-php) ```php $fh = $share->append('test.txt'); fwrite($fh, 'bar'); @@ -127,11 +126,22 @@ $options->setTimeout(5); $serverFactory = new ServerFactory($options); ``` +### Setting protocol version + +```php +$options = new Options(); +$options->setMinProtocol(IOptions::PROTOCOL_SMB2); +$options->setMaxProtocol(IOptions::PROTOCOL_SMB3); +$serverFactory = new ServerFactory($options); +``` + +Note, setting the protocol version is not supported with php-smbclient version 1.0.1 or lower. + ### Customizing system integration The `smbclient` backend needs to get various information about the system it's running on to function such as the paths of various binaries or the system timezone. -While the default logic for getting this information should work on most systems, it possible to customize this behaviour. +While the default logic for getting this information should work on most systems, it is possible to customize this behaviour. In order to customize the integration you provide a custom implementation of `ITimezoneProvider` and/or `ISystem` and pass them as arguments to the `ServerFactory`. diff --git a/apps/files_external/3rdparty/icewind/smb/composer.json b/apps/files_external/3rdparty/icewind/smb/composer.json index 02cd629565..6ab6100af7 100644 --- a/apps/files_external/3rdparty/icewind/smb/composer.json +++ b/apps/files_external/3rdparty/icewind/smb/composer.json @@ -1,29 +1,37 @@ { - "name" : "icewind/smb", - "description" : "php wrapper for smbclient and libsmbclient-php", - "license" : "MIT", - "authors" : [ - { - "name" : "Robin Appelman", - "email": "icewind@owncloud.com" - } - ], - "require" : { - "php": ">=7.1", - "icewind/streams": ">=0.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.0", - "friendsofphp/php-cs-fixer": "^2.13" - }, - "autoload" : { - "psr-4": { - "Icewind\\SMB\\": "src/" - } - }, - "autoload-dev" : { - "psr-4": { - "Icewind\\SMB\\Test\\": "tests/" - } - } + "name": "icewind/smb", + "description": "php wrapper for smbclient and libsmbclient-php", + "license": "MIT", + "authors": [ + { + "name": "Robin Appelman", + "email": "icewind@owncloud.com" + } + ], + "require": { + "php": ">=7.2", + "icewind/streams": ">=0.7.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5|^9.3.8", + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.57", + "psalm/phar": "^4.3" + }, + "autoload": { + "psr-4": { + "Icewind\\SMB\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Icewind\\SMB\\Test\\": "tests/" + } + }, + "scripts": { + "lint": "parallel-lint --exclude src --exclude vendor --exclude target --exclude build .", + "cs:check": "php-cs-fixer fix --dry-run --diff", + "cs:fix": "php-cs-fixer fix", + "psalm": "psalm.phar" + } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/ACL.php b/apps/files_external/3rdparty/icewind/smb/src/ACL.php index bdb77257f1..0b5b05a86a 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/ACL.php +++ b/apps/files_external/3rdparty/icewind/smb/src/ACL.php @@ -33,8 +33,11 @@ class ACL { const FLAG_OBJECT_INHERIT = 0x1; const FLAG_CONTAINER_INHERIT = 0x2; + /** @var int */ private $type; + /** @var int */ private $flags; + /** @var int */ private $mask; public function __construct(int $type, int $flags, int $mask) { diff --git a/apps/files_external/3rdparty/icewind/smb/src/AbstractServer.php b/apps/files_external/3rdparty/icewind/smb/src/AbstractServer.php index aa2adfa67b..810ca807d9 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/AbstractServer.php +++ b/apps/files_external/3rdparty/icewind/smb/src/AbstractServer.php @@ -24,24 +24,16 @@ namespace Icewind\SMB; abstract class AbstractServer implements IServer { const LOCALE = 'en_US.UTF-8'; - /** - * @var string $host - */ + /** @var string */ protected $host; - /** - * @var IAuth $user - */ + /** @var IAuth */ protected $auth; - /** - * @var ISystem - */ + /** @var ISystem */ protected $system; - /** - * @var TimeZoneProvider - */ + /** @var ITimeZoneProvider */ protected $timezoneProvider; /** @var IOptions */ @@ -51,10 +43,10 @@ abstract class AbstractServer implements IServer { * @param string $host * @param IAuth $auth * @param ISystem $system - * @param TimeZoneProvider $timeZoneProvider + * @param ITimeZoneProvider $timeZoneProvider * @param IOptions $options */ - public function __construct($host, IAuth $auth, ISystem $system, TimeZoneProvider $timeZoneProvider, IOptions $options) { + public function __construct(string $host, IAuth $auth, ISystem $system, ITimeZoneProvider $timeZoneProvider, IOptions $options) { $this->host = $host; $this->auth = $auth; $this->system = $system; @@ -62,23 +54,23 @@ abstract class AbstractServer implements IServer { $this->options = $options; } - public function getAuth() { + public function getAuth(): IAuth { return $this->auth; } - public function getHost() { + public function getHost(): string { return $this->host; } - public function getTimeZone() { + public function getTimeZone(): string { return $this->timezoneProvider->get($this->host); } - public function getSystem() { + public function getSystem(): ISystem { return $this->system; } - public function getOptions() { + public function getOptions(): IOptions { return $this->options; } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php b/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php index b53c253be0..454eb143e4 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php @@ -10,13 +10,18 @@ namespace Icewind\SMB; use Icewind\SMB\Exception\InvalidPathException; abstract class AbstractShare implements IShare { + /** @var string[] */ private $forbiddenCharacters; public function __construct() { $this->forbiddenCharacters = ['?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r"]; } - protected function verifyPath($path) { + /** + * @param string $path + * @throws InvalidPathException + */ + protected function verifyPath(string $path): void { foreach ($this->forbiddenCharacters as $char) { if (strpos($path, $char) !== false) { throw new InvalidPathException('Invalid path, "' . $char . '" is not allowed'); @@ -24,7 +29,10 @@ abstract class AbstractShare implements IShare { } } - public function setForbiddenChars(array $charList) { + /** + * @param string[] $charList + */ + public function setForbiddenChars(array $charList): void { $this->forbiddenCharacters = $charList; } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/AnonymousAuth.php b/apps/files_external/3rdparty/icewind/smb/src/AnonymousAuth.php index 737cc7c63f..0f3524002b 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/AnonymousAuth.php +++ b/apps/files_external/3rdparty/icewind/smb/src/AnonymousAuth.php @@ -22,23 +22,23 @@ namespace Icewind\SMB; class AnonymousAuth implements IAuth { - public function getUsername() { + public function getUsername(): ?string { return null; } - public function getWorkgroup() { + public function getWorkgroup(): ?string { return 'dummy'; } - public function getPassword() { + public function getPassword(): ?string { return null; } - public function getExtraCommandLineArguments() { + public function getExtraCommandLineArguments(): string { return '-N'; } - public function setExtraSmbClientOptions($smbClientState) { + public function setExtraSmbClientOptions($smbClientState): void { smbclient_option_set($smbClientState, SMBCLIENT_OPT_AUTO_ANONYMOUS_LOGIN, true); } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/BasicAuth.php b/apps/files_external/3rdparty/icewind/smb/src/BasicAuth.php index 9d7f9b5d30..04004e6ebd 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/BasicAuth.php +++ b/apps/files_external/3rdparty/icewind/smb/src/BasicAuth.php @@ -24,41 +24,34 @@ namespace Icewind\SMB; class BasicAuth implements IAuth { /** @var string */ private $username; - /** @var string */ + /** @var string|null */ private $workgroup; /** @var string */ private $password; - /** - * BasicAuth constructor. - * - * @param string $username - * @param string $workgroup - * @param string $password - */ - public function __construct($username, $workgroup, $password) { + public function __construct(string $username, ?string $workgroup, string $password) { $this->username = $username; $this->workgroup = $workgroup; $this->password = $password; } - public function getUsername() { + public function getUsername(): ?string { return $this->username; } - public function getWorkgroup() { + public function getWorkgroup(): ?string { return $this->workgroup; } - public function getPassword() { + public function getPassword(): ?string { return $this->password; } - public function getExtraCommandLineArguments() { + public function getExtraCommandLineArguments(): string { return ($this->workgroup) ? '-W ' . escapeshellarg($this->workgroup) : ''; } - public function setExtraSmbClientOptions($smbClientState) { + public function setExtraSmbClientOptions($smbClientState): void { // noop } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Change.php b/apps/files_external/3rdparty/icewind/smb/src/Change.php index 9dfd57b397..4d6ab49d2b 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Change.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Change.php @@ -9,32 +9,21 @@ namespace Icewind\SMB; class Change { + /** @var int */ private $code; - + /** @var string */ private $path; - /** - * Change constructor. - * - * @param $code - * @param $path - */ - public function __construct($code, $path) { + public function __construct(int $code, string $path) { $this->code = $code; $this->path = $path; } - /** - * @return integer - */ - public function getCode() { + public function getCode(): int { return $this->code; } - /** - * @return string - */ - public function getPath() { + public function getPath(): string { return $this->path; } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php index 4954518f98..e3e860b30d 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php @@ -7,23 +7,37 @@ namespace Icewind\SMB\Exception; +use Throwable; + +/** + * @psalm-consistent-constructor + */ class Exception extends \Exception { - public static function unknown($path, $error) { - $message = 'Unknown error (' . $error . ')'; + public function __construct(string $message = "", int $code = 0, Throwable $previous = null) { + parent::__construct($message, $code, $previous); + } + + /** + * @param string|null $path + * @param string|int|null $error + * @return Exception + */ + public static function unknown(?string $path, $error): Exception { + $message = 'Unknown error (' . (string)$error . ')'; if ($path) { $message .= ' for ' . $path; } - return new Exception($message, is_string($error) ? 0 : $error); + return new Exception($message, is_int($error) ? $error : 0); } /** - * @param array $exceptionMap - * @param mixed $error - * @param string $path + * @param array> $exceptionMap + * @param string|int|null $error + * @param string|null $path * @return Exception */ - public static function fromMap(array $exceptionMap, $error, $path) { + public static function fromMap(array $exceptionMap, $error, ?string $path): Exception { if (isset($exceptionMap[$error])) { $exceptionClass = $exceptionMap[$error]; if (is_numeric($error)) { diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidRequestException.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidRequestException.php index 882bf1677b..1494de9efc 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidRequestException.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidRequestException.php @@ -13,15 +13,11 @@ class InvalidRequestException extends Exception { */ protected $path; - /** - * @param string $path - * @param int $code - */ - public function __construct($path, $code = 0) { + public function __construct(string $path = "", int $code = 0, \Throwable $previous = null) { $class = get_class($this); $parts = explode('\\', $class); $baseName = array_pop($parts); - parent::__construct('Invalid request for ' . $path . ' (' . $baseName . ')', $code); + parent::__construct('Invalid request for ' . $path . ' (' . $baseName . ')', $code, $previous); $this->path = $path; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php index e898b5a234..3c7c180bf9 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php @@ -10,7 +10,7 @@ namespace Icewind\SMB\Exception; use Throwable; class RevisionMismatchException extends Exception { - public function __construct($message = 'Protocol version mismatch', $code = 0, Throwable $previous = null) { + public function __construct(string $message = 'Protocol version mismatch', int $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/IAuth.php b/apps/files_external/3rdparty/icewind/smb/src/IAuth.php index 731b315eba..9d4302dd4e 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IAuth.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IAuth.php @@ -22,32 +22,23 @@ namespace Icewind\SMB; interface IAuth { - /** - * @return string|null - */ - public function getUsername(); + public function getUsername(): ?string; - /** - * @return string|null - */ - public function getWorkgroup(); + public function getWorkgroup(): ?string; - /** - * @return string|null - */ - public function getPassword(); + public function getPassword(): ?string; /** * Any extra command line option for smbclient that are required * * @return string */ - public function getExtraCommandLineArguments(); + public function getExtraCommandLineArguments(): string; /** * Set any extra options for libsmbclient that are required * * @param resource $smbClientState */ - public function setExtraSmbClientOptions($smbClientState); + public function setExtraSmbClientOptions($smbClientState): void; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/IFileInfo.php b/apps/files_external/3rdparty/icewind/smb/src/IFileInfo.php index 3411d498d7..7e440c1420 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IFileInfo.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IFileInfo.php @@ -21,50 +21,23 @@ interface IFileInfo { const MODE_ARCHIVE = 0x20; const MODE_NORMAL = 0x80; - /** - * @return string - */ - public function getPath(); + public function getPath(): string; - /** - * @return string - */ - public function getName(); + public function getName(): string; - /** - * @return int - */ - public function getSize(); + public function getSize(): int; - /** - * @return int - */ - public function getMTime(); + public function getMTime(): int; - /** - * @return bool - */ - public function isDirectory(); + public function isDirectory(): bool; - /** - * @return bool - */ - public function isReadOnly(); + public function isReadOnly(): bool; - /** - * @return bool - */ - public function isHidden(); + public function isHidden(): bool; - /** - * @return bool - */ - public function isSystem(); + public function isSystem(): bool; - /** - * @return bool - */ - public function isArchived(); + public function isArchived(): bool; /** * @return ACL[] diff --git a/apps/files_external/3rdparty/icewind/smb/src/INotifyHandler.php b/apps/files_external/3rdparty/icewind/smb/src/INotifyHandler.php index c3ee3ffe8c..e964a15fa3 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/INotifyHandler.php +++ b/apps/files_external/3rdparty/icewind/smb/src/INotifyHandler.php @@ -25,21 +25,21 @@ interface INotifyHandler { * * @return Change[] */ - public function getChanges(); + public function getChanges(): array; /** * Listen actively to all incoming changes * * Note that this is a blocking process and will cause the process to block forever if not explicitly terminated * - * @param callable $callback + * @param callable(Change):?bool $callback */ - public function listen($callback); + public function listen(callable $callback): void; /** * Stop listening for changes * * Note that any pending changes will be discarded */ - public function stop(); + public function stop(): void; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/IOptions.php b/apps/files_external/3rdparty/icewind/smb/src/IOptions.php index c46d2c8b3d..4ab7b26c66 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IOptions.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IOptions.php @@ -22,8 +22,20 @@ namespace Icewind\SMB; interface IOptions { - /** - * @return int - */ - public function getTimeout(); + const PROTOCOL_NT1 = 'NT1'; + const PROTOCOL_SMB2 = 'SMB2'; + const PROTOCOL_SMB2_02 = 'SMB2_02'; + const PROTOCOL_SMB2_22 = 'SMB2_22'; + const PROTOCOL_SMB2_24 = 'SMB2_24'; + const PROTOCOL_SMB3 = 'SMB3'; + const PROTOCOL_SMB3_00 = 'SMB3_00'; + const PROTOCOL_SMB3_02 = 'SMB3_02'; + const PROTOCOL_SMB3_10 = 'SMB3_10'; + const PROTOCOL_SMB3_11 = 'SMB3_11'; + + public function getTimeout(): int; + + public function getMinProtocol(): ?string; + + public function getMaxProtocol(): ?string; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/IServer.php b/apps/files_external/3rdparty/icewind/smb/src/IServer.php index 0b832025aa..c2f5a504bc 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IServer.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IServer.php @@ -22,15 +22,9 @@ namespace Icewind\SMB; interface IServer { - /** - * @return IAuth - */ - public function getAuth(); + public function getAuth(): IAuth; - /** - * @return string - */ - public function getHost(); + public function getHost(): string; /** * @return \Icewind\SMB\IShare[] @@ -38,32 +32,15 @@ interface IServer { * @throws \Icewind\SMB\Exception\AuthenticationException * @throws \Icewind\SMB\Exception\InvalidHostException */ - public function listShares(); + public function listShares(): array; - /** - * @param string $name - * @return \Icewind\SMB\IShare - */ - public function getShare($name); + public function getShare(string $name): IShare; - /** - * @return string - */ - public function getTimeZone(); + public function getTimeZone(): string; - /** - * @return ISystem - */ - public function getSystem(); + public function getSystem(): ISystem; - /** - * @return IOptions - */ - public function getOptions(); + public function getOptions(): IOptions; - /** - * @param ISystem $system - * @return bool - */ - public static function available(ISystem $system); + public static function available(ISystem $system): bool; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/IShare.php b/apps/files_external/3rdparty/icewind/smb/src/IShare.php index d33d10bb3f..6ac6e0d2d1 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IShare.php @@ -7,13 +7,18 @@ namespace Icewind\SMB; +use Icewind\SMB\Exception\AlreadyExistsException; +use Icewind\SMB\Exception\InvalidRequestException; +use Icewind\SMB\Exception\InvalidTypeException; +use Icewind\SMB\Exception\NotFoundException; + interface IShare { /** * Get the name of the share * * @return string */ - public function getName(); + public function getName(): string; /** * Download a remote file @@ -22,10 +27,10 @@ interface IShare { * @param string $target local file * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function get($source, $target); + public function get(string $source, string $target): bool; /** * Upload a local file @@ -34,10 +39,10 @@ interface IShare { * @param string $target remove file * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function put($source, $target); + public function put(string $source, string $target): bool; /** * Open a readable stream top a remote file @@ -45,10 +50,10 @@ interface IShare { * @param string $source * @return resource a read only stream with the contents of the remote file * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function read($source); + public function read(string $source); /** * Open a writable stream to a remote file @@ -57,10 +62,10 @@ interface IShare { * @param string $target * @return resource a write only stream to upload a remote file * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function write($target); + public function write(string $target); /** * Open a writable stream to a remote file and set the cursor to the end of the file @@ -68,11 +73,11 @@ interface IShare { * @param string $target * @return resource a write only stream to upload a remote file * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException - * @throws \Icewind\SMB\Exception\InvalidRequestException + * @throws NotFoundException + * @throws InvalidTypeException + * @throws InvalidRequestException */ - public function append($target); + public function append(string $target); /** * Rename a remote file @@ -81,10 +86,10 @@ interface IShare { * @param string $to * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws NotFoundException + * @throws AlreadyExistsException */ - public function rename($from, $to); + public function rename(string $from, string $to): bool; /** * Delete a file on the share @@ -92,29 +97,29 @@ interface IShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function del($path); + public function del(string $path): bool; /** * List the content of a remote folder * - * @param $path - * @return \Icewind\SMB\IFileInfo[] + * @param string $path + * @return IFileInfo[] * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function dir($path); + public function dir(string $path): array; /** * @param string $path - * @return \Icewind\SMB\IFileInfo + * @return IFileInfo * - * @throws \Icewind\SMB\Exception\NotFoundException + * @throws NotFoundException */ - public function stat($path); + public function stat(string $path): IFileInfo; /** * Create a folder on the share @@ -122,10 +127,10 @@ interface IShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws NotFoundException + * @throws AlreadyExistsException */ - public function mkdir($path); + public function mkdir(string $path): bool; /** * Remove a folder on the share @@ -133,23 +138,23 @@ interface IShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function rmdir($path); + public function rmdir(string $path): bool; /** * @param string $path * @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL * @return mixed */ - public function setMode($path, $mode); + public function setMode(string $path, int $mode); /** * @param string $path * @return INotifyHandler */ - public function notify($path); + public function notify(string $path); /** * Get the IServer instance for this share diff --git a/apps/files_external/3rdparty/icewind/smb/src/ISystem.php b/apps/files_external/3rdparty/icewind/smb/src/ISystem.php index 0999461071..6f06b8421c 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/ISystem.php +++ b/apps/files_external/3rdparty/icewind/smb/src/ISystem.php @@ -32,47 +32,47 @@ interface ISystem { * @param int $num the file descriptor id * @return string */ - public function getFD($num); + public function getFD(int $num): string; /** - * Get the full path to the `smbclient` binary of false if the binary is not available + * Get the full path to the `smbclient` binary of null if the binary is not available * - * @return string|bool + * @return string|null */ - public function getSmbclientPath(); + public function getSmbclientPath(): ?string; /** - * Get the full path to the `net` binary of false if the binary is not available + * Get the full path to the `net` binary of null if the binary is not available * - * @return string|bool + * @return string|null */ - public function getNetPath(); + public function getNetPath(): ?string; /** - * Get the full path to the `smbcacls` binary of false if the binary is not available + * Get the full path to the `smbcacls` binary of null if the binary is not available * - * @return string|bool + * @return string|null */ - public function getSmbcAclsPath(); + public function getSmbcAclsPath(): ?string; /** - * Get the full path to the `stdbuf` binary of false if the binary is not available + * Get the full path to the `stdbuf` binary of null if the binary is not available * - * @return string|bool + * @return string|null */ - public function getStdBufPath(); + public function getStdBufPath(): ?string; /** - * Get the full path to the `date` binary of false if the binary is not available + * Get the full path to the `date` binary of null if the binary is not available * - * @return string|bool + * @return string|null */ - public function getDatePath(); + public function getDatePath(): ?string; /** * Whether or not the smbclient php extension is enabled * * @return bool */ - public function libSmbclientAvailable(); + public function libSmbclientAvailable(): bool; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/ITimeZoneProvider.php b/apps/files_external/3rdparty/icewind/smb/src/ITimeZoneProvider.php index 56e09ffb39..d624bcec85 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/ITimeZoneProvider.php +++ b/apps/files_external/3rdparty/icewind/smb/src/ITimeZoneProvider.php @@ -28,5 +28,5 @@ interface ITimeZoneProvider { * @param string $host * @return string */ - public function get($host); + public function get(string $host): string; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/KerberosAuth.php b/apps/files_external/3rdparty/icewind/smb/src/KerberosAuth.php index 0e91202cb7..7cd9258465 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/KerberosAuth.php +++ b/apps/files_external/3rdparty/icewind/smb/src/KerberosAuth.php @@ -25,23 +25,23 @@ namespace Icewind\SMB; * Use existing kerberos ticket to authenticate */ class KerberosAuth implements IAuth { - public function getUsername() { + public function getUsername(): ?string { return 'dummy'; } - public function getWorkgroup() { + public function getWorkgroup(): ?string { return 'dummy'; } - public function getPassword() { + public function getPassword(): ?string { return null; } - public function getExtraCommandLineArguments() { + public function getExtraCommandLineArguments(): string { return '-k'; } - public function setExtraSmbClientOptions($smbClientState) { + public function setExtraSmbClientOptions($smbClientState): void { smbclient_option_set($smbClientState, SMBCLIENT_OPT_USE_KERBEROS, true); smbclient_option_set($smbClientState, SMBCLIENT_OPT_FALLBACK_AFTER_KERBEROS, false); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeFileInfo.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeFileInfo.php index d8be57c731..539bb72842 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeFileInfo.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeFileInfo.php @@ -8,88 +8,71 @@ namespace Icewind\SMB\Native; use Icewind\SMB\ACL; +use Icewind\SMB\Exception\Exception; use Icewind\SMB\IFileInfo; class NativeFileInfo implements IFileInfo { - /** - * @var string - */ + /** @var string */ protected $path; - - /** - * @var string - */ + /** @var string */ protected $name; - - /** - * @var NativeShare - */ + /** @var NativeShare */ protected $share; - - /** - * @var array|null - */ + /** @var array{"mode": int, "size": int, "write_time": int}|null */ protected $attributeCache = null; - /** - * @param NativeShare $share - * @param string $path - * @param string $name - */ - public function __construct($share, $path, $name) { + public function __construct(NativeShare $share, string $path, string $name) { $this->share = $share; $this->path = $path; $this->name = $name; } - /** - * @return string - */ - public function getPath() { + public function getPath(): string { return $this->path; } - /** - * @return string - */ - public function getName() { + public function getName(): string { return $this->name; } /** - * @return array + * @return array{"mode": int, "size": int, "write_time": int} */ - protected function stat() { + protected function stat(): array { if (is_null($this->attributeCache)) { $rawAttributes = explode(',', $this->share->getAttribute($this->path, 'system.dos_attr.*')); - $this->attributeCache = []; + $attributes = []; foreach ($rawAttributes as $rawAttribute) { list($name, $value) = explode(':', $rawAttribute); $name = strtolower($name); if ($name == 'mode') { - $this->attributeCache[$name] = (int)hexdec(substr($value, 2)); + $attributes[$name] = (int)hexdec(substr($value, 2)); } else { - $this->attributeCache[$name] = (int)$value; + $attributes[$name] = (int)$value; } } + if (!isset($attributes['mode'])) { + throw new Exception("Invalid attribute response"); + } + if (!isset($attributes['size'])) { + throw new Exception("Invalid attribute response"); + } + if (!isset($attributes['write_time'])) { + throw new Exception("Invalid attribute response"); + } + $this->attributeCache = $attributes; } return $this->attributeCache; } - /** - * @return int - */ - public function getSize() { + public function getSize(): int { $stat = $this->stat(); return $stat['size']; } - /** - * @return int - */ - public function getMTime() { + public function getMTime(): int { $stat = $this->stat(); - return $stat['change_time']; + return $stat['write_time']; } /** @@ -104,22 +87,16 @@ class NativeFileInfo implements IFileInfo { * as false (except for `hidden` where we use the unix dotfile convention) */ - /** - * @return int - */ - protected function getMode() { + protected function getMode(): int { $mode = $this->stat()['mode']; // Let us ignore the ATTR_NOT_CONTENT_INDEXED for now $mode &= ~0x00002000; - + return $mode; } - /** - * @return bool - */ - public function isDirectory() { + public function isDirectory(): bool { $mode = $this->getMode(); if ($mode > 0x1000) { return (bool)($mode & 0x4000); // 0x4000: unix directory flag @@ -128,10 +105,7 @@ class NativeFileInfo implements IFileInfo { } } - /** - * @return bool - */ - public function isReadOnly() { + public function isReadOnly(): bool { $mode = $this->getMode(); if ($mode > 0x1000) { return !(bool)($mode & 0x80); // 0x80: owner write permissions @@ -140,10 +114,7 @@ class NativeFileInfo implements IFileInfo { } } - /** - * @return bool - */ - public function isHidden() { + public function isHidden(): bool { $mode = $this->getMode(); if ($mode > 0x1000) { return strlen($this->name) > 0 && $this->name[0] === '.'; @@ -152,10 +123,7 @@ class NativeFileInfo implements IFileInfo { } } - /** - * @return bool - */ - public function isSystem() { + public function isSystem(): bool { $mode = $this->getMode(); if ($mode > 0x1000) { return false; @@ -164,10 +132,7 @@ class NativeFileInfo implements IFileInfo { } } - /** - * @return bool - */ - public function isArchived() { + public function isArchived(): bool { $mode = $this->getMode(); if ($mode > 0x1000) { return false; @@ -185,10 +150,11 @@ class NativeFileInfo implements IFileInfo { foreach (explode(',', $attribute) as $acl) { list($user, $permissions) = explode(':', $acl, 2); + $user = trim($user, '\\'); list($type, $flags, $mask) = explode('/', $permissions); $mask = hexdec($mask); - $acls[$user] = new ACL($type, $flags, $mask); + $acls[$user] = new ACL((int)$type, (int)$flags, (int)$mask); } return $acls; diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeReadStream.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeReadStream.php index fe0af760d3..f39ec4db39 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeReadStream.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeReadStream.php @@ -7,64 +7,54 @@ namespace Icewind\SMB\Native; +use Icewind\SMB\StringBuffer; + /** * Stream optimized for read only usage */ class NativeReadStream extends NativeStream { const CHUNK_SIZE = 1048576; // 1MB chunks - /** - * @var resource - */ - private $readBuffer = null; - private $bufferSize = 0; + /** @var StringBuffer */ + private $readBuffer; + public function __construct() { + $this->readBuffer = new StringBuffer(); + } + + /** @var int */ private $pos = 0; public function stream_open($path, $mode, $options, &$opened_path) { - $this->readBuffer = fopen('php://memory', 'r+'); - return parent::stream_open($path, $mode, $options, $opened_path); } /** * Wrap a stream from libsmbclient-php into a regular php stream * - * @param \Icewind\SMB\NativeState $state + * @param NativeState $state * @param resource $smbStream * @param string $mode * @param string $url * @return resource */ - public static function wrap($state, $smbStream, $mode, $url) { - stream_wrapper_register('nativesmb', NativeReadStream::class); - $context = stream_context_create([ - 'nativesmb' => [ - 'state' => $state, - 'handle' => $smbStream, - 'url' => $url - ] - ]); - $fh = fopen('nativesmb://', $mode, false, $context); - stream_wrapper_unregister('nativesmb'); - return $fh; + public static function wrap(NativeState $state, $smbStream, string $mode, string $url) { + return parent::wrapClass($state, $smbStream, $mode, $url, NativeReadStream::class); } public function stream_read($count) { // php reads 8192 bytes at once // however due to network latency etc, it's faster to read in larger chunks // and buffer the result - if (!parent::stream_eof() && $this->bufferSize < $count) { - $remaining = $this->readBuffer; - $this->readBuffer = fopen('php://memory', 'r+'); - $this->bufferSize = 0; - stream_copy_to_stream($remaining, $this->readBuffer); - $this->bufferSize += fwrite($this->readBuffer, parent::stream_read(self::CHUNK_SIZE)); - fseek($this->readBuffer, 0); + if (!parent::stream_eof() && $this->readBuffer->remaining() < $count) { + $chunk = parent::stream_read(self::CHUNK_SIZE); + if ($chunk === false) { + return false; + } + $this->readBuffer->push($chunk); } - $result = fread($this->readBuffer, $count); - $this->bufferSize -= $count; + $result = $this->readBuffer->read($count); $read = strlen($result); $this->pos += $read; @@ -75,15 +65,18 @@ class NativeReadStream extends NativeStream { public function stream_seek($offset, $whence = SEEK_SET) { $result = parent::stream_seek($offset, $whence); if ($result) { - $this->readBuffer = fopen('php://memory', 'r+'); - $this->bufferSize = 0; - $this->pos = parent::stream_tell(); + $this->readBuffer->clear(); + $pos = parent::stream_tell(); + if ($pos === false) { + return false; + } + $this->pos = $pos; } return $result; } public function stream_eof() { - return $this->bufferSize <= 0 && parent::stream_eof(); + return $this->readBuffer->remaining() <= 0 && parent::stream_eof(); } public function stream_tell() { diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeServer.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeServer.php index aadb05d0fe..68b6c46ca2 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeServer.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeServer.php @@ -8,10 +8,13 @@ namespace Icewind\SMB\Native; use Icewind\SMB\AbstractServer; +use Icewind\SMB\Exception\AuthenticationException; +use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\IAuth; use Icewind\SMB\IOptions; +use Icewind\SMB\IShare; use Icewind\SMB\ISystem; -use Icewind\SMB\TimeZoneProvider; +use Icewind\SMB\ITimeZoneProvider; class NativeServer extends AbstractServer { /** @@ -19,38 +22,34 @@ class NativeServer extends AbstractServer { */ protected $state; - public function __construct($host, IAuth $auth, ISystem $system, TimeZoneProvider $timeZoneProvider, IOptions $options) { + public function __construct(string $host, IAuth $auth, ISystem $system, ITimeZoneProvider $timeZoneProvider, IOptions $options) { parent::__construct($host, $auth, $system, $timeZoneProvider, $options); $this->state = new NativeState(); } - protected function connect() { + protected function connect(): void { $this->state->init($this->getAuth(), $this->getOptions()); } /** - * @return \Icewind\SMB\IShare[] - * @throws \Icewind\SMB\Exception\AuthenticationException - * @throws \Icewind\SMB\Exception\InvalidHostException + * @return IShare[] + * @throws AuthenticationException + * @throws InvalidHostException */ - public function listShares() { + public function listShares(): array { $this->connect(); $shares = []; $dh = $this->state->opendir('smb://' . $this->getHost()); - while ($share = $this->state->readdir($dh)) { + while ($share = $this->state->readdir($dh, '')) { if ($share['type'] === 'file share') { $shares[] = $this->getShare($share['name']); } } - $this->state->closedir($dh); + $this->state->closedir($dh, ''); return $shares; } - /** - * @param string $name - * @return \Icewind\SMB\IShare - */ - public function getShare($name) { + public function getShare(string $name): IShare { return new NativeShare($this, $name); } @@ -60,7 +59,7 @@ class NativeServer extends AbstractServer { * @param ISystem $system * @return bool */ - public static function available(ISystem $system) { + public static function available(ISystem $system): bool { return $system->libSmbclientAvailable(); } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeShare.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeShare.php index 5368538edc..03ec501b83 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeShare.php @@ -8,9 +8,16 @@ namespace Icewind\SMB\Native; use Icewind\SMB\AbstractShare; +use Icewind\SMB\Exception\AlreadyExistsException; +use Icewind\SMB\Exception\AuthenticationException; +use Icewind\SMB\Exception\ConnectionException; use Icewind\SMB\Exception\DependencyException; +use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\Exception\InvalidPathException; use Icewind\SMB\Exception\InvalidResourceException; +use Icewind\SMB\Exception\InvalidTypeException; +use Icewind\SMB\Exception\NotFoundException; +use Icewind\SMB\IFileInfo; use Icewind\SMB\INotifyHandler; use Icewind\SMB\IServer; use Icewind\SMB\Wrapped\Server; @@ -27,28 +34,22 @@ class NativeShare extends AbstractShare { */ private $name; - /** - * @var NativeState $state - */ - private $state; + /** @var NativeState|null $state */ + private $state = null; - /** - * @param IServer $server - * @param string $name - */ - public function __construct($server, $name) { + public function __construct(IServer $server, string $name) { parent::__construct(); $this->server = $server; $this->name = $name; } /** - * @throws \Icewind\SMB\Exception\ConnectionException - * @throws \Icewind\SMB\Exception\AuthenticationException - * @throws \Icewind\SMB\Exception\InvalidHostException + * @throws ConnectionException + * @throws AuthenticationException + * @throws InvalidHostException */ - protected function getState() { - if ($this->state and $this->state instanceof NativeState) { + protected function getState(): NativeState { + if ($this->state) { return $this->state; } @@ -62,11 +63,11 @@ class NativeShare extends AbstractShare { * * @return string */ - public function getName() { + public function getName(): string { return $this->name; } - private function buildUrl($path) { + private function buildUrl(string $path): string { $this->verifyPath($path); $url = sprintf('smb://%s/%s', $this->server->getHost(), $this->name); if ($path) { @@ -81,16 +82,16 @@ class NativeShare extends AbstractShare { * List the content of a remote folder * * @param string $path - * @return \Icewind\SMB\IFileInfo[] + * @return IFileInfo[] * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function dir($path) { + public function dir(string $path): array { $files = []; $dh = $this->getState()->opendir($this->buildUrl($path)); - while ($file = $this->getState()->readdir($dh)) { + while ($file = $this->getState()->readdir($dh, $path)) { $name = $file['name']; if ($name !== '.' and $name !== '..') { $fullPath = $path . '/' . $name; @@ -98,15 +99,15 @@ class NativeShare extends AbstractShare { } } - $this->getState()->closedir($dh); + $this->getState()->closedir($dh, $path); return $files; } /** * @param string $path - * @return \Icewind\SMB\IFileInfo + * @return IFileInfo */ - public function stat($path) { + public function stat(string $path): IFileInfo { $info = new NativeFileInfo($this, $path, self::mb_basename($path)); // trigger attribute loading @@ -119,10 +120,10 @@ class NativeShare extends AbstractShare { * Multibyte unicode safe version of basename() * * @param string $path - * @link https://www.php.net/manual/en/function.basename.php#121405 + * @link http://php.net/manual/en/function.basename.php#121405 * @return string */ - protected static function mb_basename($path) { + protected static function mb_basename(string $path): string { if (preg_match('@^.*[\\\\/]([^\\\\/]+)$@s', $path, $matches)) { return $matches[1]; } elseif (preg_match('@^([^\\\\/]+)$@s', $path, $matches)) { @@ -138,10 +139,10 @@ class NativeShare extends AbstractShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws NotFoundException + * @throws AlreadyExistsException */ - public function mkdir($path) { + public function mkdir(string $path): bool { return $this->getState()->mkdir($this->buildUrl($path)); } @@ -151,10 +152,10 @@ class NativeShare extends AbstractShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function rmdir($path) { + public function rmdir(string $path): bool { return $this->getState()->rmdir($this->buildUrl($path)); } @@ -164,10 +165,10 @@ class NativeShare extends AbstractShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function del($path) { + public function del(string $path): bool { return $this->getState()->unlink($this->buildUrl($path)); } @@ -178,10 +179,10 @@ class NativeShare extends AbstractShare { * @param string $to * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws NotFoundException + * @throws AlreadyExistsException */ - public function rename($from, $to) { + public function rename(string $from, string $to): bool { return $this->getState()->rename($this->buildUrl($from), $this->buildUrl($to)); } @@ -192,10 +193,10 @@ class NativeShare extends AbstractShare { * @param string $target remove file * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function put($source, $target) { + public function put(string $source, string $target): bool { $sourceHandle = fopen($source, 'rb'); $targetUrl = $this->buildUrl($target); @@ -215,20 +216,18 @@ class NativeShare extends AbstractShare { * @param string $target local file * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException - * @throws \Icewind\SMB\Exception\InvalidPathException - * @throws \Icewind\SMB\Exception\InvalidResourceException + * @throws AuthenticationException + * @throws ConnectionException + * @throws InvalidHostException + * @throws InvalidPathException + * @throws InvalidResourceException */ - public function get($source, $target) { + public function get(string $source, string $target): bool { if (!$target) { throw new InvalidPathException('Invalid target path: Filename cannot be empty'); } $sourceHandle = $this->getState()->open($this->buildUrl($source), 'r'); - if (!$sourceHandle) { - throw new InvalidResourceException('Failed opening remote file "' . $source . '" for reading'); - } $targetHandle = @fopen($target, 'wb'); if (!$targetHandle) { @@ -242,7 +241,7 @@ class NativeShare extends AbstractShare { throw new InvalidResourceException('Failed opening local file "' . $target . '" for writing: ' . $reason); } - while ($data = $this->getState()->read($sourceHandle, NativeReadStream::CHUNK_SIZE)) { + while ($data = $this->getState()->read($sourceHandle, NativeReadStream::CHUNK_SIZE, $source)) { fwrite($targetHandle, $data); } $this->getState()->close($sourceHandle, $this->buildUrl($source)); @@ -255,10 +254,10 @@ class NativeShare extends AbstractShare { * @param string $source * @return resource a read only stream with the contents of the remote file * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function read($source) { + public function read(string $source) { $url = $this->buildUrl($source); $handle = $this->getState()->open($url, 'r'); return NativeReadStream::wrap($this->getState(), $handle, 'r', $url); @@ -271,10 +270,10 @@ class NativeShare extends AbstractShare { * @param string $source * @return resource a writeable stream * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function write($source) { + public function write(string $source) { $url = $this->buildUrl($source); $handle = $this->getState()->create($url); return NativeWriteStream::wrap($this->getState(), $handle, 'w', $url); @@ -286,10 +285,10 @@ class NativeShare extends AbstractShare { * @param string $source * @return resource a writeable stream * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function append($source) { + public function append(string $source) { $url = $this->buildUrl($source); $handle = $this->getState()->open($url, "a+"); return NativeWriteStream::wrap($this->getState(), $handle, "a", $url); @@ -302,7 +301,7 @@ class NativeShare extends AbstractShare { * @param string $attribute attribute to get the info * @return string the attribute value */ - public function getAttribute($path, $attribute) { + public function getAttribute(string $path, string $attribute): string { return $this->getState()->getxattr($this->buildUrl($path), $attribute); } @@ -314,9 +313,13 @@ class NativeShare extends AbstractShare { * @param string|int $value * @return mixed the attribute value */ - public function setAttribute($path, $attribute, $value) { - if ($attribute === 'system.dos_attr.mode' and is_int($value)) { - $value = '0x' . dechex($value); + public function setAttribute(string $path, string $attribute, $value) { + if (is_int($value)) { + if ($attribute === 'system.dos_attr.mode') { + $value = '0x' . dechex($value); + } else { + throw new \InvalidArgumentException("Invalid value for attribute"); + } } return $this->getState()->setxattr($this->buildUrl($path), $attribute, $value); @@ -329,7 +332,7 @@ class NativeShare extends AbstractShare { * @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL * @return mixed */ - public function setMode($path, $mode) { + public function setMode(string $path, int $mode) { return $this->setAttribute($path, 'system.dos_attr.mode', $mode); } @@ -340,7 +343,7 @@ class NativeShare extends AbstractShare { * @param string $path * @return INotifyHandler */ - public function notify($path) { + public function notify(string $path): INotifyHandler { // php-smbclient does not support notify (https://github.com/eduardok/libsmbclient-php/issues/29) // so we use the smbclient based backend for this if (!Server::available($this->server->getSystem())) { diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeState.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeState.php index 3bfb1c3da2..10ba6ce045 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeState.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeState.php @@ -29,13 +29,13 @@ use Icewind\SMB\IOptions; * Low level wrapper for libsmbclient-php with error handling */ class NativeState { - /** - * @var resource - */ - protected $state; + /** @var resource|null */ + protected $state = null; + /** @var bool */ protected $handlerSet = false; + /** @var bool */ protected $connected = false; // see error.h @@ -58,7 +58,8 @@ class NativeState { 113 => NoRouteToHostException::class ]; - protected function handleError($path) { + protected function handleError(?string $path): void { + /** @var int $error */ $error = smbclient_state_errno($this->state); if ($error === 0) { return; @@ -66,14 +67,19 @@ class NativeState { throw Exception::fromMap(self::EXCEPTION_MAP, $error, $path); } - protected function testResult($result, $uri) { + /** + * @param mixed $result + * @param string|null $uri + * @throws Exception + */ + protected function testResult($result, ?string $uri): void { if ($result === false or $result === null) { // smb://host/share/path if (is_string($uri) && count(explode('/', $uri, 5)) > 4) { list(, , , , $path) = explode('/', $uri, 5); $path = '/' . $path; } else { - $path = null; + $path = $uri; } $this->handleError($path); } @@ -88,10 +94,21 @@ class NativeState { if ($this->connected) { return true; } - $this->state = smbclient_state_new(); + /** @var resource $state */ + $state = smbclient_state_new(); + $this->state = $state; smbclient_option_set($this->state, SMBCLIENT_OPT_AUTO_ANONYMOUS_LOGIN, false); smbclient_option_set($this->state, SMBCLIENT_OPT_TIMEOUT, $options->getTimeout() * 1000); + + if (function_exists('smbclient_client_protocols')) { + $maxProtocol = $options->getMaxProtocol(); + $minProtocol = $options->getMinProtocol(); + + smbclient_client_protocols($this->state, $minProtocol, $maxProtocol); + } + $auth->setExtraSmbClientOptions($this->state); + /** @var bool $result */ $result = @smbclient_state_init($this->state, $auth->getWorkgroup(), $auth->getUsername(), $auth->getPassword()); $this->testResult($result, ''); @@ -103,7 +120,8 @@ class NativeState { * @param string $uri * @return resource */ - public function opendir($uri) { + public function opendir(string $uri) { + /** @var resource $result */ $result = @smbclient_opendir($this->state, $uri); $this->testResult($result, $uri); @@ -112,23 +130,27 @@ class NativeState { /** * @param resource $dir - * @return array + * @param string $path + * @return array{"type": string, "comment": string, "name": string}|false */ - public function readdir($dir) { + public function readdir($dir, string $path) { + /** @var array{"type": string, "comment": string, "name": string}|false $result */ $result = @smbclient_readdir($this->state, $dir); - $this->testResult($result, $dir); + $this->testResult($result, $path); return $result; } /** - * @param $dir + * @param resource $dir + * @param string $path * @return bool */ - public function closedir($dir) { + public function closedir($dir, string $path): bool { + /** @var bool $result */ $result = smbclient_closedir($this->state, $dir); - $this->testResult($result, $dir); + $this->testResult($result, $path); return $result; } @@ -137,7 +159,8 @@ class NativeState { * @param string $new * @return bool */ - public function rename($old, $new) { + public function rename(string $old, string $new): bool { + /** @var bool $result */ $result = @smbclient_rename($this->state, $old, $this->state, $new); $this->testResult($result, $new); @@ -148,7 +171,8 @@ class NativeState { * @param string $uri * @return bool */ - public function unlink($uri) { + public function unlink(string $uri): bool { + /** @var bool $result */ $result = @smbclient_unlink($this->state, $uri); $this->testResult($result, $uri); @@ -160,7 +184,8 @@ class NativeState { * @param int $mask * @return bool */ - public function mkdir($uri, $mask = 0777) { + public function mkdir(string $uri, int $mask = 0777): bool { + /** @var bool $result */ $result = @smbclient_mkdir($this->state, $uri, $mask); $this->testResult($result, $uri); @@ -171,7 +196,8 @@ class NativeState { * @param string $uri * @return bool */ - public function rmdir($uri) { + public function rmdir(string $uri): bool { + /** @var bool $result */ $result = @smbclient_rmdir($this->state, $uri); $this->testResult($result, $uri); @@ -180,9 +206,10 @@ class NativeState { /** * @param string $uri - * @return array + * @return array{"mtime": int, "size": int, "mode": int} */ - public function stat($uri) { + public function stat(string $uri): array { + /** @var array{"mtime": int, "size": int, "mode": int} $result */ $result = @smbclient_stat($this->state, $uri); $this->testResult($result, $uri); @@ -191,12 +218,14 @@ class NativeState { /** * @param resource $file - * @return array + * @param string $path + * @return array{"mtime": int, "size": int, "mode": int} */ - public function fstat($file) { + public function fstat($file, string $path): array { + /** @var array{"mtime": int, "size": int, "mode": int} $result */ $result = @smbclient_fstat($this->state, $file); - $this->testResult($result, $file); + $this->testResult($result, $path); return $result; } @@ -206,7 +235,8 @@ class NativeState { * @param int $mask * @return resource */ - public function open($uri, $mode, $mask = 0666) { + public function open(string $uri, string $mode, int $mask = 0666) { + /** @var resource $result */ $result = @smbclient_open($this->state, $uri, $mode, $mask); $this->testResult($result, $uri); @@ -218,7 +248,8 @@ class NativeState { * @param int $mask * @return resource */ - public function create($uri, $mask = 0666) { + public function create(string $uri, int $mask = 0666) { + /** @var resource $result */ $result = @smbclient_creat($this->state, $uri, $mask); $this->testResult($result, $uri); @@ -228,12 +259,14 @@ class NativeState { /** * @param resource $file * @param int $bytes + * @param string $path * @return string */ - public function read($file, $bytes) { + public function read($file, int $bytes, string $path): string { + /** @var string $result */ $result = @smbclient_read($this->state, $file, $bytes); - $this->testResult($result, $file); + $this->testResult($result, $path); return $result; } @@ -241,10 +274,11 @@ class NativeState { * @param resource $file * @param string $data * @param string $path - * @param int $length + * @param int|null $length * @return int */ - public function write($file, $data, $path, $length = null) { + public function write($file, string $data, string $path, ?int $length = null): int { + /** @var int $result */ $result = @smbclient_write($this->state, $file, $data, $length); $this->testResult($result, $path); @@ -255,28 +289,38 @@ class NativeState { * @param resource $file * @param int $offset * @param int $whence SEEK_SET | SEEK_CUR | SEEK_END - * @return int|bool new file offset as measured from the start of the file on success, false on failure. + * @param string|null $path + * @return int|false new file offset as measured from the start of the file on success. */ - public function lseek($file, $offset, $whence = SEEK_SET) { + public function lseek($file, int $offset, int $whence = SEEK_SET, string $path = null) { + /** @var int|false $result */ $result = @smbclient_lseek($this->state, $file, $offset, $whence); - $this->testResult($result, $file); + $this->testResult($result, $path); return $result; } /** * @param resource $file * @param int $size + * @param string $path * @return bool */ - public function ftruncate($file, $size) { + public function ftruncate($file, int $size, string $path): bool { + /** @var bool $result */ $result = @smbclient_ftruncate($this->state, $file, $size); - $this->testResult($result, $file); + $this->testResult($result, $path); return $result; } - public function close($file, $path) { + /** + * @param resource $file + * @param string $path + * @return bool + */ + public function close($file, string $path): bool { + /** @var bool $result */ $result = @smbclient_close($this->state, $file); $this->testResult($result, $path); @@ -288,7 +332,8 @@ class NativeState { * @param string $key * @return string */ - public function getxattr($uri, $key) { + public function getxattr(string $uri, string $key) { + /** @var string $result */ $result = @smbclient_getxattr($this->state, $uri, $key); $this->testResult($result, $uri); @@ -300,9 +345,10 @@ class NativeState { * @param string $key * @param string $value * @param int $flags - * @return mixed + * @return bool */ - public function setxattr($uri, $key, $value, $flags = 0) { + public function setxattr(string $uri, string $key, string $value, int $flags = 0) { + /** @var bool $result */ $result = @smbclient_setxattr($this->state, $uri, $key, $value, $flags); $this->testResult($result, $uri); diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeStream.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeStream.php index c75afaa5f1..216c27f78e 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeStream.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeStream.php @@ -10,20 +10,24 @@ namespace Icewind\SMB\Native; use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\InvalidRequestException; use Icewind\Streams\File; +use InvalidArgumentException; -class NativeStream implements File { +abstract class NativeStream implements File { /** * @var resource + * @psalm-suppress PropertyNotSetInConstructor */ public $context; /** * @var NativeState + * @psalm-suppress PropertyNotSetInConstructor */ protected $state; /** * @var resource + * @psalm-suppress PropertyNotSetInConstructor */ protected $handle; @@ -35,19 +39,20 @@ class NativeStream implements File { /** * @var string */ - protected $url; + protected $url = ''; /** * Wrap a stream from libsmbclient-php into a regular php stream * - * @param \Icewind\SMB\NativeState $state + * @param NativeState $state * @param resource $smbStream * @param string $mode * @param string $url + * @param class-string $class * @return resource */ - public static function wrap($state, $smbStream, $mode, $url) { - stream_wrapper_register('nativesmb', NativeStream::class); + protected static function wrapClass(NativeState $state, $smbStream, string $mode, string $url, string $class) { + stream_wrapper_register('nativesmb', $class); $context = stream_context_create([ 'nativesmb' => [ 'state' => $state, @@ -73,19 +78,35 @@ class NativeStream implements File { } public function stream_flush() { + return false; } public function stream_open($path, $mode, $options, &$opened_path) { $context = stream_context_get_options($this->context); - $this->state = $context['nativesmb']['state']; - $this->handle = $context['nativesmb']['handle']; - $this->url = $context['nativesmb']['url']; + if (!isset($context['nativesmb']) || !is_array($context['nativesmb'])) { + throw new InvalidArgumentException("context not set"); + } + $state = $context['nativesmb']['state']; + if (!$state instanceof NativeState) { + throw new InvalidArgumentException("invalid context set"); + } + $this->state = $state; + $handle = $context['nativesmb']['handle']; + if (!is_resource($handle)) { + throw new InvalidArgumentException("invalid context set"); + } + $this->handle = $handle; + $url = $context['nativesmb']['url']; + if (!is_string($url)) { + throw new InvalidArgumentException("invalid context set"); + } + $this->url = $url; return true; } public function stream_read($count) { - $result = $this->state->read($this->handle, $count); + $result = $this->state->read($this->handle, $count, $this->url); if (strlen($result) < $count) { $this->eof = true; } @@ -95,12 +116,15 @@ class NativeStream implements File { public function stream_seek($offset, $whence = SEEK_SET) { $this->eof = false; try { - return $this->state->lseek($this->handle, $offset, $whence) !== false; + return $this->state->lseek($this->handle, $offset, $whence, $this->url) !== false; } catch (InvalidRequestException $e) { return false; } } + /** + * @return array{"mtime": int, "size": int, "mode": int}|false + */ public function stream_stat() { try { return $this->state->stat($this->url); @@ -110,7 +134,7 @@ class NativeStream implements File { } public function stream_tell() { - return $this->state->lseek($this->handle, 0, SEEK_CUR); + return $this->state->lseek($this->handle, 0, SEEK_CUR, $this->url); } public function stream_write($data) { @@ -118,7 +142,7 @@ class NativeStream implements File { } public function stream_truncate($size) { - return $this->state->ftruncate($this->handle, $size); + return $this->state->ftruncate($this->handle, $size, $this->url); } public function stream_set_option($option, $arg1, $arg2) { diff --git a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeWriteStream.php b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeWriteStream.php index 4e90e5a655..7c27499764 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Native/NativeWriteStream.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Native/NativeWriteStream.php @@ -7,71 +7,63 @@ namespace Icewind\SMB\Native; +use Icewind\SMB\StringBuffer; + /** * Stream optimized for write only usage */ class NativeWriteStream extends NativeStream { const CHUNK_SIZE = 1048576; // 1MB chunks - /** - * @var resource - */ - private $writeBuffer = null; - private $bufferSize = 0; + /** @var StringBuffer */ + private $writeBuffer; + /** @var int */ private $pos = 0; - public function stream_open($path, $mode, $options, &$opened_path) { - $this->writeBuffer = fopen('php://memory', 'r+'); + public function __construct() { + $this->writeBuffer = new StringBuffer(); + } + public function stream_open($path, $mode, $options, &$opened_path): bool { return parent::stream_open($path, $mode, $options, $opened_path); } /** * Wrap a stream from libsmbclient-php into a regular php stream * - * @param \Icewind\SMB\NativeState $state + * @param NativeState $state * @param resource $smbStream * @param string $mode * @param string $url * @return resource */ - public static function wrap($state, $smbStream, $mode, $url) { - stream_wrapper_register('nativesmb', NativeWriteStream::class); - $context = stream_context_create([ - 'nativesmb' => [ - 'state' => $state, - 'handle' => $smbStream, - 'url' => $url - ] - ]); - $fh = fopen('nativesmb://', $mode, false, $context); - stream_wrapper_unregister('nativesmb'); - return $fh; + public static function wrap(NativeState $state, $smbStream, string $mode, string $url) { + return parent::wrapClass($state, $smbStream, $mode, $url, NativeWriteStream::class); } public function stream_seek($offset, $whence = SEEK_SET) { $this->flushWrite(); $result = parent::stream_seek($offset, $whence); if ($result) { - $this->pos = parent::stream_tell(); + $pos = parent::stream_tell(); + if ($pos === false) { + return false; + } + $this->pos = $pos; } return $result; } - private function flushWrite() { - rewind($this->writeBuffer); - $this->state->write($this->handle, stream_get_contents($this->writeBuffer), $this->url); - $this->writeBuffer = fopen('php://memory', 'r+'); - $this->bufferSize = 0; + private function flushWrite(): void { + parent::stream_write($this->writeBuffer->flush()); } public function stream_write($data) { - $written = fwrite($this->writeBuffer, $data); - $this->bufferSize += $written; + $written = $this->writeBuffer->push($data); $this->pos += $written; - if ($this->bufferSize >= self::CHUNK_SIZE) { + if ($this->writeBuffer->remaining() >= self::CHUNK_SIZE) { $this->flushWrite(); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Options.php b/apps/files_external/3rdparty/icewind/smb/src/Options.php index 7a0d0149b7..f590594b99 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Options.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Options.php @@ -25,11 +25,32 @@ class Options implements IOptions { /** @var int */ private $timeout = 20; - public function getTimeout() { + /** @var string|null */ + private $minProtocol; + /** @var string|null */ + private $maxProtocol; + + public function getTimeout(): int { return $this->timeout; } - public function setTimeout($timeout) { + public function setTimeout(int $timeout): void { $this->timeout = $timeout; } + + public function getMinProtocol(): ?string { + return $this->minProtocol; + } + + public function setMinProtocol(?string $minProtocol): void { + $this->minProtocol = $minProtocol; + } + + public function getMaxProtocol(): ?string { + return $this->maxProtocol; + } + + public function setMaxProtocol(?string $maxProtocol): void { + $this->maxProtocol = $maxProtocol; + } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/ServerFactory.php b/apps/files_external/3rdparty/icewind/smb/src/ServerFactory.php index 807b0b872c..4c579d0684 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/ServerFactory.php +++ b/apps/files_external/3rdparty/icewind/smb/src/ServerFactory.php @@ -31,7 +31,7 @@ class ServerFactory { Server::class ]; - /** @var System */ + /** @var ISystem */ private $system; /** @var IOptions */ @@ -68,12 +68,12 @@ class ServerFactory { /** - * @param $host + * @param string $host * @param IAuth $credentials * @return IServer * @throws DependencyException */ - public function createServer($host, IAuth $credentials) { + public function createServer(string $host, IAuth $credentials): IServer { foreach (self::BACKENDS as $backend) { if (call_user_func("$backend::available", $this->system)) { return new $backend($host, $credentials, $this->system, $this->timeZoneProvider, $this->options); diff --git a/apps/files_external/3rdparty/icewind/smb/src/StringBuffer.php b/apps/files_external/3rdparty/icewind/smb/src/StringBuffer.php new file mode 100644 index 0000000000..8566121876 --- /dev/null +++ b/apps/files_external/3rdparty/icewind/smb/src/StringBuffer.php @@ -0,0 +1,63 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace Icewind\SMB; + +class StringBuffer { + /** @var string */ + private $buffer = ""; + /** @var int */ + private $pos = 0; + + public function clear(): void { + $this->buffer = ""; + $this->pos = 0; + } + + public function push(string $data): int { + $this->buffer = $this->flush() . $data; + return strlen($data); + } + + public function remaining(): int { + return strlen($this->buffer) - $this->pos; + } + + public function read(int $count): string { + $chunk = substr($this->buffer, $this->pos, $this->pos + $count); + $this->pos += strlen($chunk); + return $chunk; + } + + public function flush(): string { + if ($this->pos === 0) { + $remaining = $this->buffer; + } else { + $remaining = substr($this->buffer, $this->pos); + } + + $this->clear(); + + return $remaining; + } +} diff --git a/apps/files_external/3rdparty/icewind/smb/src/System.php b/apps/files_external/3rdparty/icewind/smb/src/System.php index 0e41ee032d..919907477a 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/System.php +++ b/apps/files_external/3rdparty/icewind/smb/src/System.php @@ -10,7 +10,7 @@ namespace Icewind\SMB; use Icewind\SMB\Exception\Exception; class System implements ISystem { - /** @var (string|bool)[] */ + /** @var (string|null)[] */ private $paths = []; /** @@ -20,7 +20,7 @@ class System implements ISystem { * @return string * @throws Exception */ - public function getFD($num) { + public function getFD(int $num): string { $folders = [ '/proc/self/fd', '/dev/fd' @@ -33,36 +33,36 @@ class System implements ISystem { throw new Exception('Cant find file descriptor path'); } - public function getSmbclientPath() { + public function getSmbclientPath(): ?string { return $this->getBinaryPath('smbclient'); } - public function getNetPath() { + public function getNetPath(): ?string { return $this->getBinaryPath('net'); } - public function getSmbcAclsPath() { + public function getSmbcAclsPath(): ?string { return $this->getBinaryPath('smbcacls'); } - public function getStdBufPath() { + public function getStdBufPath(): ?string { return $this->getBinaryPath('stdbuf'); } - public function getDatePath() { + public function getDatePath(): ?string { return $this->getBinaryPath('date'); } - public function libSmbclientAvailable() { + public function libSmbclientAvailable(): bool { return function_exists('smbclient_state_new'); } - protected function getBinaryPath($binary) { + protected function getBinaryPath(string $binary): ?string { if (!isset($this->paths[$binary])) { $result = null; $output = []; exec("which $binary 2>&1", $output, $result); - $this->paths[$binary] = $result === 0 ? trim(implode('', $output)) : false; + $this->paths[$binary] = $result === 0 ? trim(implode('', $output)) : null; } return $this->paths[$binary]; } diff --git a/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php b/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php index 7ae049c406..4cd3b65681 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php +++ b/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php @@ -25,7 +25,7 @@ class TimeZoneProvider implements ITimeZoneProvider { $this->system = $system; } - public function get($host) { + public function get(string $host): string { if (!isset($this->timeZones[$host])) { $timeZone = null; $net = $this->system->getNetPath(); diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Connection.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Connection.php index 347b63db11..31b72b05d9 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Connection.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Connection.php @@ -7,9 +7,11 @@ namespace Icewind\SMB\Wrapped; +use Icewind\SMB\Exception\AccessDeniedException; use Icewind\SMB\Exception\AuthenticationException; use Icewind\SMB\Exception\ConnectException; use Icewind\SMB\Exception\ConnectionException; +use Icewind\SMB\Exception\ConnectionRefusedException; use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\Exception\NoLoginServerException; @@ -20,7 +22,12 @@ class Connection extends RawConnection { /** @var Parser */ private $parser; - public function __construct($command, Parser $parser, $env = []) { + /** + * @param string $command + * @param Parser $parser + * @param array $env + */ + public function __construct(string $command, Parser $parser, array $env = []) { parent::__construct($command, $env); $this->parser = $parser; } @@ -30,39 +37,48 @@ class Connection extends RawConnection { * * @param string $input */ - public function write($input) { - parent::write($input . PHP_EOL); + public function write(string $input) { + return parent::write($input . PHP_EOL); } /** * @throws ConnectException */ - public function clearTillPrompt() { + public function clearTillPrompt(): void { $this->write(''); do { $promptLine = $this->readLine(); + if ($promptLine === false) { + break; + } $this->parser->checkConnectionError($promptLine); } while (!$this->isPrompt($promptLine)); - $this->write(''); + if ($this->write('') === false) { + throw new ConnectionRefusedException(); + } $this->readLine(); } /** * get all unprocessed output from smbclient until the next prompt * - * @param callable $callback (optional) callback to call for every line read + * @param (callable(string):bool)|null $callback (optional) callback to call for every line read * @return string[] * @throws AuthenticationException * @throws ConnectException * @throws ConnectionException * @throws InvalidHostException * @throws NoLoginServerException + * @throws AccessDeniedException */ - public function read(callable $callback = null) { + public function read(callable $callback = null): array { if (!$this->isValid()) { throw new ConnectionException('Connection not valid'); } $promptLine = $this->readLine(); //first line is prompt + if ($promptLine === false) { + $this->unknownError($promptLine); + } $this->parser->checkConnectionError($promptLine); $output = []; @@ -74,7 +90,7 @@ class Connection extends RawConnection { if ($line === false) { $this->unknownError($promptLine); } - while (!$this->isPrompt($line)) { //next prompt functions as delimiter + while ($line !== false && !$this->isPrompt($line)) { //next prompt functions as delimiter if (is_callable($callback)) { $result = $callback($line); if ($result === false) { // allow the callback to close the connection for infinite running commands @@ -82,26 +98,21 @@ class Connection extends RawConnection { break; } } else { - $output[] .= $line; + $output[] = $line; } $line = $this->readLine(); } return $output; } - /** - * Check - * - * @param $line - * @return bool - */ - private function isPrompt($line) { - return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER || $line === false; + private function isPrompt(string $line): bool { + return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER; } /** - * @param string $promptLine (optional) prompt line that might contain some info about the error + * @param string|bool $promptLine (optional) prompt line that might contain some info about the error * @throws ConnectException + * @return no-return */ private function unknownError($promptLine = '') { if ($promptLine) { //maybe we have some error we missed on the previous line @@ -116,7 +127,7 @@ class Connection extends RawConnection { } } - public function close($terminate = true) { + public function close(bool $terminate = true): void { if (get_resource_type($this->getInputStream()) === 'stream') { // ignore any errors while trying to send the close command, the process might already be dead @$this->write('close' . PHP_EOL); diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/FileInfo.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/FileInfo.php index a310a6bc91..de5a696df7 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/FileInfo.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/FileInfo.php @@ -11,34 +11,17 @@ use Icewind\SMB\ACL; use Icewind\SMB\IFileInfo; class FileInfo implements IFileInfo { - /** - * @var string - */ + /** @var string */ protected $path; - - /** - * @var string - */ + /** @var string */ protected $name; - - /** - * @var int - */ + /** @var int */ protected $size; - - /** - * @var int - */ + /** @var int */ protected $time; - - /** - * @var int - */ + /** @var int */ protected $mode; - - /** - * @var callable - */ + /** @var callable(): ACL[] */ protected $aclCallback; /** @@ -47,9 +30,9 @@ class FileInfo implements IFileInfo { * @param int $size * @param int $time * @param int $mode - * @param callable $aclCallback + * @param callable(): ACL[] $aclCallback */ - public function __construct($path, $name, $size, $time, $mode, callable $aclCallback) { + public function __construct(string $path, string $name, int $size, int $time, int $mode, callable $aclCallback) { $this->path = $path; $this->name = $name; $this->size = $size; @@ -61,63 +44,39 @@ class FileInfo implements IFileInfo { /** * @return string */ - public function getPath() { + public function getPath(): string { return $this->path; } - /** - * @return string - */ - public function getName() { + public function getName(): string { return $this->name; } - /** - * @return int - */ - public function getSize() { + public function getSize(): int { return $this->size; } - /** - * @return int - */ - public function getMTime() { + public function getMTime(): int { return $this->time; } - /** - * @return bool - */ - public function isDirectory() { + public function isDirectory(): bool { return (bool)($this->mode & IFileInfo::MODE_DIRECTORY); } - /** - * @return bool - */ - public function isReadOnly() { + public function isReadOnly(): bool { return (bool)($this->mode & IFileInfo::MODE_READONLY); } - /** - * @return bool - */ - public function isHidden() { + public function isHidden(): bool { return (bool)($this->mode & IFileInfo::MODE_HIDDEN); } - /** - * @return bool - */ - public function isSystem() { + public function isSystem(): bool { return (bool)($this->mode & IFileInfo::MODE_SYSTEM); } - /** - * @return bool - */ - public function isArchived() { + public function isArchived(): bool { return (bool)($this->mode & IFileInfo::MODE_ARCHIVE); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/NotifyHandler.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/NotifyHandler.php index 090734381b..18451f4daa 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/NotifyHandler.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/NotifyHandler.php @@ -14,16 +14,13 @@ use Icewind\SMB\Exception\RevisionMismatchException; use Icewind\SMB\INotifyHandler; class NotifyHandler implements INotifyHandler { - /** - * @var Connection - */ + /** @var Connection */ private $connection; - /** - * @var string - */ + /** @var string */ private $path; + /** @var bool */ private $listening = true; // see error.h @@ -35,7 +32,7 @@ class NotifyHandler implements INotifyHandler { * @param Connection $connection * @param string $path */ - public function __construct(Connection $connection, $path) { + public function __construct(Connection $connection, string $path) { $this->connection = $connection; $this->path = $path; } @@ -45,17 +42,17 @@ class NotifyHandler implements INotifyHandler { * * @return Change[] */ - public function getChanges() { + public function getChanges(): array { if (!$this->listening) { return []; } - stream_set_blocking($this->connection->getOutputStream(), 0); + stream_set_blocking($this->connection->getOutputStream(), false); $lines = []; while (($line = $this->connection->readLine())) { $this->checkForError($line); $lines[] = $line; } - stream_set_blocking($this->connection->getOutputStream(), 1); + stream_set_blocking($this->connection->getOutputStream(), true); return array_values(array_filter(array_map([$this, 'parseChangeLine'], $lines))); } @@ -64,21 +61,24 @@ class NotifyHandler implements INotifyHandler { * * Note that this is a blocking process and will cause the process to block forever if not explicitly terminated * - * @param callable $callback + * @param callable(Change):?bool $callback */ - public function listen($callback) { + public function listen(callable $callback): void { if ($this->listening) { - $this->connection->read(function ($line) use ($callback) { + $this->connection->read(function (string $line) use ($callback): bool { $this->checkForError($line); $change = $this->parseChangeLine($line); if ($change) { - return $callback($change); + $result = $callback($change); + return $result === false ? false : true; + } else { + return true; } }); } } - private function parseChangeLine($line) { + private function parseChangeLine(string $line): ?Change { $code = (int)substr($line, 0, 4); if ($code === 0) { return null; @@ -91,14 +91,14 @@ class NotifyHandler implements INotifyHandler { } } - private function checkForError($line) { + private function checkForError(string $line): void { if (substr($line, 0, 16) === 'notify returned ') { $error = substr($line, 16); throw Exception::fromMap(array_merge(self::EXCEPTION_MAP, Parser::EXCEPTION_MAP), $error, 'Notify is not supported with the used smb version'); } } - public function stop() { + public function stop(): void { $this->listening = false; $this->connection->close(); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Parser.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Parser.php index a28432e431..ec14ac4b1f 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Parser.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Parser.php @@ -7,6 +7,7 @@ namespace Icewind\SMB\Wrapped; +use Icewind\SMB\ACL; use Icewind\SMB\Exception\AccessDeniedException; use Icewind\SMB\Exception\AlreadyExistsException; use Icewind\SMB\Exception\AuthenticationException; @@ -28,11 +29,6 @@ class Parser { */ protected $timeZone; - /** - * @var string - */ - private $host; - // see error.h const EXCEPTION_MAP = [ ErrorCodes::LogonFailure => AuthenticationException::class, @@ -60,21 +56,29 @@ class Parser { /** * @param string $timeZone */ - public function __construct($timeZone) { + public function __construct(string $timeZone) { $this->timeZone = $timeZone; } - private function getErrorCode($line) { + private function getErrorCode(string $line): ?string { $parts = explode(' ', $line); foreach ($parts as $part) { if (substr($part, 0, 9) === 'NT_STATUS') { return $part; } } - return false; + return null; } - public function checkForError($output, $path) { + /** + * @param string[] $output + * @param string $path + * @return no-return + * @throws Exception + * @throws InvalidResourceException + * @throws NotFoundException + */ + public function checkForError(array $output, string $path): void { if (strpos($output[0], 'does not exist')) { throw new NotFoundException($path); } @@ -91,13 +95,13 @@ class Parser { /** * check if the first line holds a connection failure * - * @param $line + * @param string $line * @throws AuthenticationException * @throws InvalidHostException * @throws NoLoginServerException * @throws AccessDeniedException */ - public function checkConnectionError($line) { + public function checkConnectionError(string $line): void { $line = rtrim($line, ')'); if (substr($line, -23) === ErrorCodes::LogonFailure) { throw new AuthenticationException('Invalid login'); @@ -119,7 +123,7 @@ class Parser { } } - public function parseMode($mode) { + public function parseMode(string $mode): int { $result = 0; foreach (self::MODE_STRINGS as $char => $val) { if (strpos($mode, $char) !== false) { @@ -129,7 +133,12 @@ class Parser { return $result; } - public function parseStat($output) { + /** + * @param string[] $output + * @return array{"mtime": int, "mode": int, "size": int} + * @throws Exception + */ + public function parseStat(array $output): array { $data = []; foreach ($output as $line) { // A line = explode statement may not fill all array elements @@ -143,14 +152,24 @@ class Parser { $data[$name] = $value; } } + $attributeStart = strpos($data['attributes'], '('); + if ($attributeStart === false) { + throw new Exception("Malformed state response from server"); + } return [ 'mtime' => strtotime($data['write_time']), - 'mode' => hexdec(substr($data['attributes'], strpos($data['attributes'], '(') + 1, -1)), + 'mode' => hexdec(substr($data['attributes'], $attributeStart + 1, -1)), 'size' => isset($data['stream']) ? (int)(explode(' ', $data['stream'])[1]) : 0 ]; } - public function parseDir($output, $basePath, callable $aclCallback) { + /** + * @param string[] $output + * @param string $basePath + * @param callable(string):ACL[] $aclCallback + * @return FileInfo[] + */ + public function parseDir(array $output, string $basePath, callable $aclCallback): array { //last line is used space array_pop($output); $regex = '/^\s*(.*?)\s\s\s\s+(?:([NDHARS]*)\s+)?([0-9]+)\s+(.*)$/'; @@ -163,7 +182,7 @@ class Parser { $mode = $this->parseMode($mode); $time = strtotime($time . ' ' . $this->timeZone); $path = $basePath . '/' . $name; - $content[] = new FileInfo($path, $name, $size, $time, $mode, function () use ($aclCallback, $path) { + $content[] = new FileInfo($path, $name, (int)$size, $time, $mode, function () use ($aclCallback, $path): array { return $aclCallback($path); }); } @@ -172,7 +191,11 @@ class Parser { return $content; } - public function parseListShares($output) { + /** + * @param string[] $output + * @return array + */ + public function parseListShares(array $output): array { $shareNames = []; foreach ($output as $line) { if (strpos($line, '|')) { @@ -188,4 +211,67 @@ class Parser { } return $shareNames; } + + /** + * @param string[] $rawAcls + * @return ACL[] + */ + public function parseACLs(array $rawAcls): array { + $acls = []; + foreach ($rawAcls as $acl) { + if (strpos($acl, ':') === false) { + continue; + } + [$type, $acl] = explode(':', $acl, 2); + if ($type !== 'ACL') { + continue; + } + [$user, $permissions] = explode(':', $acl, 2); + [$type, $flags, $mask] = explode('/', $permissions); + + $type = $type === 'ALLOWED' ? ACL::TYPE_ALLOW : ACL::TYPE_DENY; + + $flagsInt = 0; + foreach (explode('|', $flags) as $flagString) { + if ($flagString === 'OI') { + $flagsInt += ACL::FLAG_OBJECT_INHERIT; + } elseif ($flagString === 'CI') { + $flagsInt += ACL::FLAG_CONTAINER_INHERIT; + } + } + + if (substr($mask, 0, 2) === '0x') { + $maskInt = hexdec($mask); + } else { + $maskInt = 0; + foreach (explode('|', $mask) as $maskString) { + if ($maskString === 'R') { + $maskInt += ACL::MASK_READ; + } elseif ($maskString === 'W') { + $maskInt += ACL::MASK_WRITE; + } elseif ($maskString === 'X') { + $maskInt += ACL::MASK_EXECUTE; + } elseif ($maskString === 'D') { + $maskInt += ACL::MASK_DELETE; + } elseif ($maskString === 'READ') { + $maskInt += ACL::MASK_READ + ACL::MASK_EXECUTE; + } elseif ($maskString === 'CHANGE') { + $maskInt += ACL::MASK_READ + ACL::MASK_EXECUTE + ACL::MASK_WRITE + ACL::MASK_DELETE; + } elseif ($maskString === 'FULL') { + $maskInt += ACL::MASK_READ + ACL::MASK_EXECUTE + ACL::MASK_WRITE + ACL::MASK_DELETE; + } + } + } + + if (isset($acls[$user])) { + $existing = $acls[$user]; + $maskInt += $existing->getMask(); + } + $acls[$user] = new ACL($type, $flagsInt, $maskInt); + } + + ksort($acls); + + return $acls; + } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/RawConnection.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/RawConnection.php index 3a114af5e4..26a17cc584 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/RawConnection.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/RawConnection.php @@ -30,10 +30,10 @@ class RawConnection { * $pipes[4] holds the stream for writing files * $pipes[5] holds the stream for reading files */ - private $pipes; + private $pipes = []; /** - * @var resource $process + * @var resource|null $process */ private $process; @@ -42,17 +42,20 @@ class RawConnection { */ private $authStream = null; - private $connected = false; - - public function __construct($command, array $env = []) { + /** + * @param string $command + * @param array $env + */ + public function __construct(string $command, array $env = []) { $this->command = $command; $this->env = $env; } /** * @throws ConnectException + * @psalm-assert resource $this->process */ - public function connect() { + public function connect(): void { if (is_null($this->getAuthStream())) { throw new ConnectException('Authentication not set before connecting'); } @@ -77,18 +80,18 @@ class RawConnection { if (!$this->isValid()) { throw new ConnectionException(); } - $this->connected = true; } /** * check if the connection is still active * * @return bool + * @psalm-assert-if-true resource $this->process */ - public function isValid() { + public function isValid(): bool { if (is_resource($this->process)) { $status = proc_get_status($this->process); - return $status['running']; + return (bool)$status['running']; } else { return false; } @@ -98,10 +101,12 @@ class RawConnection { * send input to the process * * @param string $input + * @return int|bool */ - public function write($input) { - fwrite($this->getInputStream(), $input); + public function write(string $input) { + $result = @fwrite($this->getInputStream(), $input); fflush($this->getInputStream()); + return $result; } /** @@ -116,18 +121,19 @@ class RawConnection { /** * read a line of output * - * @return string + * @return string|false */ public function readError() { - return trim(stream_get_line($this->getErrorStream(), 4086)); + $line = stream_get_line($this->getErrorStream(), 4086); + return $line !== false ? trim($line) : false; } /** * get all output until the process closes * - * @return array + * @return string[] */ - public function readAll() { + public function readAll(): array { $output = []; while ($line = $this->readLine()) { $output[] = $line; @@ -135,40 +141,67 @@ class RawConnection { return $output; } + /** + * @return resource + */ public function getInputStream() { return $this->pipes[0]; } + /** + * @return resource + */ public function getOutputStream() { return $this->pipes[1]; } + /** + * @return resource + */ public function getErrorStream() { return $this->pipes[2]; } + /** + * @return resource|null + */ public function getAuthStream() { return $this->authStream; } + /** + * @return resource + */ public function getFileInputStream() { return $this->pipes[4]; } + /** + * @return resource + */ public function getFileOutputStream() { return $this->pipes[5]; } - public function writeAuthentication($user, $password) { - $auth = ($password === false) + /** + * @param string|null $user + * @param string|null $password + * @psalm-assert resource $this->authStream + */ + public function writeAuthentication(?string $user, ?string $password): void { + $auth = ($password === null) ? "username=$user" : "username=$user\npassword=$password\n"; $this->authStream = fopen('php://temp', 'w+'); - fwrite($this->getAuthStream(), $auth); + fwrite($this->authStream, $auth); } - public function close($terminate = true) { + /** + * @param bool $terminate + * @psalm-assert null $this->process + */ + public function close(bool $terminate = true): void { if (!is_resource($this->process)) { return; } @@ -176,9 +209,10 @@ class RawConnection { proc_terminate($this->process); } proc_close($this->process); + $this->process = null; } - public function reconnect() { + public function reconnect(): void { $this->close(); $this->connect(); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Server.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Server.php index b3763a7324..60cc9278dd 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Server.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Server.php @@ -11,6 +11,8 @@ use Icewind\SMB\AbstractServer; use Icewind\SMB\Exception\AuthenticationException; use Icewind\SMB\Exception\ConnectException; use Icewind\SMB\Exception\ConnectionException; +use Icewind\SMB\Exception\ConnectionRefusedException; +use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\IShare; use Icewind\SMB\ISystem; @@ -22,11 +24,11 @@ class Server extends AbstractServer { * @param ISystem $system * @return bool */ - public static function available(ISystem $system) { - return $system->getSmbclientPath(); + public static function available(ISystem $system): bool { + return $system->getSmbclientPath() !== null; } - private function getAuthFileArgument() { + private function getAuthFileArgument(): string { if ($this->getAuth()->getUsername()) { return '--authentication-file=' . $this->system->getFD(3); } else { @@ -41,22 +43,30 @@ class Server extends AbstractServer { * @throws InvalidHostException * @throws ConnectException */ - public function listShares() { + public function listShares(): array { + $maxProtocol = $this->options->getMaxProtocol(); + $minProtocol = $this->options->getMinProtocol(); + $smbClient = $this->system->getSmbclientPath(); + if ($smbClient === null) { + throw new Exception("Backend not available"); + } $command = sprintf( - '%s %s %s -L %s', - $this->system->getSmbclientPath(), + '%s %s %s %s %s -L %s', + $smbClient, $this->getAuthFileArgument(), $this->getAuth()->getExtraCommandLineArguments(), + $maxProtocol ? "--option='client max protocol=" . $maxProtocol . "'" : "", + $minProtocol ? "--option='client min protocol=" . $minProtocol . "'" : "", escapeshellarg('//' . $this->getHost()) ); $connection = new RawConnection($command); $connection->writeAuthentication($this->getAuth()->getUsername(), $this->getAuth()->getPassword()); $connection->connect(); if (!$connection->isValid()) { - throw new ConnectionException($connection->readLine()); + throw new ConnectionException((string)$connection->readLine()); } - $parser = new Parser($this->timezoneProvider); + $parser = new Parser($this->timezoneProvider->get($this->host)); $output = $connection->readAll(); if (isset($output[0])) { @@ -71,6 +81,9 @@ class Server extends AbstractServer { if (isset($output[0])) { $parser->checkConnectionError($output[0]); } + if (count($output) === 0) { + throw new ConnectionRefusedException(); + } $shareNames = $parser->parseListShares($output); @@ -85,7 +98,7 @@ class Server extends AbstractServer { * @param string $name * @return IShare */ - public function getShare($name) { + public function getShare(string $name): IShare { return new Share($this, $name, $this->system); } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Share.php b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Share.php index ea386a87bf..68446d380e 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Share.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Wrapped/Share.php @@ -9,9 +9,14 @@ namespace Icewind\SMB\Wrapped; use Icewind\SMB\AbstractShare; use Icewind\SMB\ACL; +use Icewind\SMB\Exception\AlreadyExistsException; +use Icewind\SMB\Exception\AuthenticationException; +use Icewind\SMB\Exception\ConnectException; use Icewind\SMB\Exception\ConnectionException; use Icewind\SMB\Exception\DependencyException; +use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\FileInUseException; +use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\Exception\InvalidTypeException; use Icewind\SMB\Exception\NotFoundException; use Icewind\SMB\Exception\InvalidRequestException; @@ -35,9 +40,9 @@ class Share extends AbstractShare { private $name; /** - * @var Connection $connection + * @var Connection|null $connection */ - public $connection; + public $connection = null; /** * @var Parser @@ -63,7 +68,7 @@ class Share extends AbstractShare { * @param string $name * @param ISystem $system */ - public function __construct(IServer $server, $name, ISystem $system) { + public function __construct(IServer $server, string $name, ISystem $system) { parent::__construct(); $this->server = $server; $this->name = $name; @@ -71,7 +76,7 @@ class Share extends AbstractShare { $this->parser = new Parser($server->getTimeZone()); } - private function getAuthFileArgument() { + private function getAuthFileArgument(): string { if ($this->server->getAuth()->getUsername()) { return '--authentication-file=' . $this->system->getFD(3); } else { @@ -79,22 +84,31 @@ class Share extends AbstractShare { } } - protected function getConnection() { + protected function getConnection(): Connection { + $maxProtocol = $this->server->getOptions()->getMaxProtocol(); + $minProtocol = $this->server->getOptions()->getMinProtocol(); + $smbClient = $this->system->getSmbclientPath(); + $stdBuf = $this->system->getStdBufPath(); + if ($smbClient === null) { + throw new Exception("Backend not available"); + } $command = sprintf( - '%s %s%s -t %s %s %s %s', + '%s %s%s -t %s %s %s %s %s %s', self::EXEC_CMD, - $this->system->getStdBufPath() ? $this->system->getStdBufPath() . ' -o0 ' : '', - $this->system->getSmbclientPath(), + $stdBuf ? $stdBuf . ' -o0 ' : '', + $smbClient, $this->server->getOptions()->getTimeout(), $this->getAuthFileArgument(), $this->server->getAuth()->getExtraCommandLineArguments(), + $maxProtocol ? "--option='client max protocol=" . $maxProtocol . "'" : "", + $minProtocol ? "--option='client min protocol=" . $minProtocol . "'" : "", escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) ); $connection = new Connection($command, $this->parser); $connection->writeAuthentication($this->server->getAuth()->getUsername(), $this->server->getAuth()->getPassword()); $connection->connect(); if (!$connection->isValid()) { - throw new ConnectionException($connection->readLine()); + throw new ConnectionException((string)$connection->readLine()); } // some versions of smbclient add a help message in first of the first prompt $connection->clearTillPrompt(); @@ -102,21 +116,33 @@ class Share extends AbstractShare { } /** - * @throws \Icewind\SMB\Exception\ConnectionException - * @throws \Icewind\SMB\Exception\AuthenticationException - * @throws \Icewind\SMB\Exception\InvalidHostException + * @throws ConnectionException + * @throws AuthenticationException + * @throws InvalidHostException + * @psalm-assert Connection $this->connection */ - protected function connect() { + protected function connect(): Connection { if ($this->connection and $this->connection->isValid()) { - return; + return $this->connection; } $this->connection = $this->getConnection(); + return $this->connection; } - protected function reconnect() { - $this->connection->reconnect(); - if (!$this->connection->isValid()) { - throw new ConnectionException(); + /** + * @throws ConnectionException + * @throws AuthenticationException + * @throws InvalidHostException + * @psalm-assert Connection $this->connection + */ + protected function reconnect(): void { + if ($this->connection === null) { + $this->connect(); + } else { + $this->connection->reconnect(); + if (!$this->connection->isValid()) { + throw new ConnectionException(); + } } } @@ -125,11 +151,11 @@ class Share extends AbstractShare { * * @return string */ - public function getName() { + public function getName(): string { return $this->name; } - protected function simpleCommand($command, $path) { + protected function simpleCommand(string $command, string $path): bool { $escapedPath = $this->escapePath($path); $cmd = $command . ' ' . $escapedPath; $output = $this->execute($cmd); @@ -139,13 +165,13 @@ class Share extends AbstractShare { /** * List the content of a remote folder * - * @param $path - * @return \Icewind\SMB\IFileInfo[] + * @param string $path + * @return IFileInfo[] * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function dir($path) { + public function dir(string $path): array { $escapedPath = $this->escapePath($path); $output = $this->execute('cd ' . $escapedPath); //check output for errors @@ -154,16 +180,16 @@ class Share extends AbstractShare { $this->execute('cd /'); - return $this->parser->parseDir($output, $path, function ($path) { + return $this->parser->parseDir($output, $path, function (string $path) { return $this->getAcls($path); }); } /** * @param string $path - * @return \Icewind\SMB\IFileInfo + * @return IFileInfo */ - public function stat($path) { + public function stat(string $path): IFileInfo { // some windows server setups don't seem to like the allinfo command // use the dir command instead to get the file info where possible if ($path !== "" && $path !== "/") { @@ -200,10 +226,10 @@ class Share extends AbstractShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws NotFoundException + * @throws AlreadyExistsException */ - public function mkdir($path) { + public function mkdir(string $path): bool { return $this->simpleCommand('mkdir', $path); } @@ -213,10 +239,10 @@ class Share extends AbstractShare { * @param string $path * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function rmdir($path) { + public function rmdir(string $path): bool { return $this->simpleCommand('rmdir', $path); } @@ -230,7 +256,7 @@ class Share extends AbstractShare { * @throws NotFoundException * @throws \Exception */ - public function del($path, $secondTry = false) { + public function del(string $path, bool $secondTry = false): bool { //del return a file not found error when trying to delete a folder //we catch it so we can check if $path doesn't exist or is of invalid type try { @@ -261,10 +287,10 @@ class Share extends AbstractShare { * @param string $to * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws NotFoundException + * @throws AlreadyExistsException */ - public function rename($from, $to) { + public function rename(string $from, string $to): bool { $path1 = $this->escapePath($from); $path2 = $this->escapePath($to); $output = $this->execute('rename ' . $path1 . ' ' . $path2); @@ -278,10 +304,10 @@ class Share extends AbstractShare { * @param string $target remove file * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function put($source, $target) { + public function put(string $source, string $target): bool { $path1 = $this->escapeLocalPath($source); //first path is local, needs different escaping $path2 = $this->escapePath($target); $output = $this->execute('put ' . $path1 . ' ' . $path2); @@ -295,10 +321,10 @@ class Share extends AbstractShare { * @param string $target local file * @return bool * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function get($source, $target) { + public function get(string $source, string $target): bool { $path1 = $this->escapePath($source); $path2 = $this->escapeLocalPath($target); //second path is local, needs different escaping $output = $this->execute('get ' . $path1 . ' ' . $path2); @@ -311,10 +337,10 @@ class Share extends AbstractShare { * @param string $source * @return resource a read only stream with the contents of the remote file * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function read($source) { + public function read(string $source) { $source = $this->escapePath($source); // since returned stream is closed by the caller we need to create a new instance // since we can't re-use the same file descriptor over multiple calls @@ -333,10 +359,10 @@ class Share extends AbstractShare { * @param string $target * @return resource a write only stream to upload a remote file * - * @throws \Icewind\SMB\Exception\NotFoundException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws NotFoundException + * @throws InvalidTypeException */ - public function write($target) { + public function write(string $target) { $target = $this->escapePath($target); // since returned stream is closed by the caller we need to create a new instance // since we can't re-use the same file descriptor over multiple calls @@ -348,9 +374,14 @@ class Share extends AbstractShare { // use a close callback to ensure the upload is finished before continuing // this also serves as a way to keep the connection in scope - return CallbackWrapper::wrap($fh, null, null, function () use ($connection, $target) { + $stream = CallbackWrapper::wrap($fh, null, null, function () use ($connection) { $connection->close(false); // dont terminate, give the upload some time }); + if (is_resource($stream)) { + return $stream; + } else { + throw new InvalidRequestException($target); + } } /** @@ -359,9 +390,9 @@ class Share extends AbstractShare { * * @param string $target * - * @throws \Icewind\SMB\Exception\DependencyException + * @throws DependencyException */ - public function append($target) { + public function append(string $target) { throw new DependencyException('php-libsmbclient is required for append'); } @@ -370,7 +401,7 @@ class Share extends AbstractShare { * @param int $mode a combination of FileInfo::MODE_READONLY, FileInfo::MODE_ARCHIVE, FileInfo::MODE_SYSTEM and FileInfo::MODE_HIDDEN, FileInfo::NORMAL * @return mixed */ - public function setMode($path, $mode) { + public function setMode(string $path, int $mode) { $modeString = ''; foreach (self::MODE_MAP as $modeByte => $string) { if ($mode & $modeByte) { @@ -400,7 +431,7 @@ class Share extends AbstractShare { * @throws ConnectionException * @throws DependencyException */ - public function notify($path) { + public function notify(string $path): INotifyHandler { if (!$this->system->getStdBufPath()) { //stdbuf is required to disable smbclient's output buffering throw new DependencyException('stdbuf is required for usage of the notify command'); } @@ -412,12 +443,11 @@ class Share extends AbstractShare { /** * @param string $command - * @return array + * @return string[] */ - protected function execute($command) { - $this->connect(); - $this->connection->write($command . PHP_EOL); - return $this->connection->read(); + protected function execute(string $command): array { + $this->connect()->write($command . PHP_EOL); + return $this->connect()->read(); } /** @@ -427,19 +457,18 @@ class Share extends AbstractShare { * @param string $path * * @return bool - * @throws \Icewind\SMB\Exception\AlreadyExistsException + * @throws AlreadyExistsException * @throws \Icewind\SMB\Exception\AccessDeniedException * @throws \Icewind\SMB\Exception\NotEmptyException - * @throws \Icewind\SMB\Exception\InvalidTypeException + * @throws InvalidTypeException * @throws \Icewind\SMB\Exception\Exception * @throws NotFoundException */ - protected function parseOutput($lines, $path = '') { + protected function parseOutput(array $lines, string $path = ''): bool { if (count($lines) === 0) { return true; } else { $this->parser->checkForError($lines, $path); - return false; } } @@ -447,7 +476,7 @@ class Share extends AbstractShare { * @param string $string * @return string */ - protected function escape($string) { + protected function escape(string $string): string { return escapeshellarg($string); } @@ -455,7 +484,7 @@ class Share extends AbstractShare { * @param string $path * @return string */ - protected function escapePath($path) { + protected function escapePath(string $path): string { $this->verifyPath($path); if ($path === '/') { $path = ''; @@ -470,12 +499,18 @@ class Share extends AbstractShare { * @param string $path * @return string */ - protected function escapeLocalPath($path) { + protected function escapeLocalPath(string $path): string { $path = str_replace('"', '\"', $path); return '"' . $path . '"'; } - protected function getAcls($path) { + /** + * @param string $path + * @return ACL[] + * @throws ConnectionException + * @throws ConnectException + */ + protected function getAcls(string $path): array { $commandPath = $this->system->getSmbcAclsPath(); if (!$commandPath) { return []; @@ -494,62 +529,11 @@ class Share extends AbstractShare { $connection->writeAuthentication($this->server->getAuth()->getUsername(), $this->server->getAuth()->getPassword()); $connection->connect(); if (!$connection->isValid()) { - throw new ConnectionException($connection->readLine()); + throw new ConnectionException((string)$connection->readLine()); } $rawAcls = $connection->readAll(); - - $acls = []; - foreach ($rawAcls as $acl) { - [$type, $acl] = explode(':', $acl, 2); - if ($type !== 'ACL') { - continue; - } - [$user, $permissions] = explode(':', $acl, 2); - [$type, $flags, $mask] = explode('/', $permissions); - - $type = $type === 'ALLOWED' ? ACL::TYPE_ALLOW : ACL::TYPE_DENY; - - $flagsInt = 0; - foreach (explode('|', $flags) as $flagString) { - if ($flagString === 'OI') { - $flagsInt += ACL::FLAG_OBJECT_INHERIT; - } elseif ($flagString === 'CI') { - $flagsInt += ACL::FLAG_CONTAINER_INHERIT; - } - } - - if (substr($mask, 0, 2) === '0x') { - $maskInt = hexdec($mask); - } else { - $maskInt = 0; - foreach (explode('|', $mask) as $maskString) { - if ($maskString === 'R') { - $maskInt += ACL::MASK_READ; - } elseif ($maskString === 'W') { - $maskInt += ACL::MASK_WRITE; - } elseif ($maskString === 'X') { - $maskInt += ACL::MASK_EXECUTE; - } elseif ($maskString === 'D') { - $maskInt += ACL::MASK_DELETE; - } elseif ($maskString === 'READ') { - $maskInt += ACL::MASK_READ + ACL::MASK_EXECUTE; - } elseif ($maskString === 'CHANGE') { - $maskInt += ACL::MASK_READ + ACL::MASK_EXECUTE + ACL::MASK_WRITE + ACL::MASK_DELETE; - } elseif ($maskString === 'FULL') { - $maskInt += ACL::MASK_READ + ACL::MASK_EXECUTE + ACL::MASK_WRITE + ACL::MASK_DELETE; - } - } - } - - if (isset($acls[$user])) { - $existing = $acls[$user]; - $maskInt += $existing->getMask(); - } - $acls[$user] = new ACL($type, $flagsInt, $maskInt); - } - - return $acls; + return $this->parser->parseACLs($rawAcls); } public function getServer(): IServer { diff --git a/apps/files_external/3rdparty/icewind/streams/.gitignore b/apps/files_external/3rdparty/icewind/streams/.gitignore index 4f389129e2..a8fa5d4a95 100644 --- a/apps/files_external/3rdparty/icewind/streams/.gitignore +++ b/apps/files_external/3rdparty/icewind/streams/.gitignore @@ -1,3 +1,6 @@ .idea vendor composer.lock +build +example.php +*.cache diff --git a/apps/files_external/3rdparty/icewind/streams/.travis.yml b/apps/files_external/3rdparty/icewind/streams/.travis.yml deleted file mode 100644 index 68efcd2c74..0000000000 --- a/apps/files_external/3rdparty/icewind/streams/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: php -php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - 7.2 - -env: - global: - - CURRENT_DIR=`pwd` - -install: - - composer install --dev --no-interaction - -script: - - mkdir -p build/logs - - cd tests - - phpunit --coverage-clover ../build/logs/clover.xml --configuration phpunit.xml - -after_script: - - cd $CURRENT_DIR - - php vendor/bin/coveralls -v diff --git a/apps/files_external/3rdparty/icewind/streams/README.md b/apps/files_external/3rdparty/icewind/streams/README.md index 88ab2dd92a..0dbafc9df0 100644 --- a/apps/files_external/3rdparty/icewind/streams/README.md +++ b/apps/files_external/3rdparty/icewind/streams/README.md @@ -1,8 +1,7 @@ # Streams # -[![Build Status](https://travis-ci.org/icewind1991/Streams.svg?branch=master)](https://travis-ci.org/icewind1991/Streams) -[![Coverage Status](https://img.shields.io/coveralls/icewind1991/Streams.svg)](https://coveralls.io/r/icewind1991/Streams?branch=master) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/icewind1991/Streams/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/icewind1991/Streams/?branch=master) +[![CI](https://github.com/icewind1991/Streams/actions/workflows/ci.yaml/badge.svg)](https://github.com/icewind1991/Streams/actions/workflows/ci.yaml) +[![codecov](https://codecov.io/gh/icewind1991/Streams/branch/master/graph/badge.svg?token=bfPcAdGAaq)](https://codecov.io/gh/icewind1991/Streams) Generic stream wrappers for php. @@ -14,7 +13,7 @@ it wraps an existing stream and can thus be used for any stream in php The callbacks are passed in the stream context along with the source stream and can be any valid [php callable](http://php.net/manual/en/language.types.callable.php) -###Example### +### Example ### ```php =5.3" + "require": { + "php": ">=7.1" }, - "require-dev" : { - "satooshi/php-coveralls": "v1.0.0", - "phpunit/phpunit": "^4.8" + "require-dev": { + "phpunit/phpunit": "^9", + "friendsofphp/php-cs-fixer": "^2", + "phpstan/phpstan": "^0.12" }, - "autoload" : { + "autoload": { "psr-4": { - "Icewind\\Streams\\Tests\\": "tests/", "Icewind\\Streams\\": "src/" } + }, + "autoload-dev": { + "psr-4": { + "Icewind\\Streams\\Tests\\": "tests/" + } } } diff --git a/apps/files_external/3rdparty/icewind/streams/src/CallbackWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/CallbackWrapper.php index 67f9110d10..5d78b5a3db 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/CallbackWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/CallbackWrapper.php @@ -25,27 +25,27 @@ namespace Icewind\Streams; */ class CallbackWrapper extends Wrapper { /** - * @var callable + * @var callable|null */ protected $readCallback; /** - * @var callable + * @var callable|null */ protected $writeCallback; /** - * @var callable + * @var callable|null */ protected $closeCallback; /** - * @var callable + * @var callable|null */ protected $readDirCallBack; /** - * @var callable + * @var callable|null */ protected $preCloseCallback; @@ -53,30 +53,28 @@ class CallbackWrapper extends Wrapper { * Wraps a stream with the provided callbacks * * @param resource $source - * @param callable $read (optional) - * @param callable $write (optional) - * @param callable $close (optional) - * @param callable $readDir (optional) - * @return resource + * @param callable|null $read (optional) + * @param callable|null $write (optional) + * @param callable|null $close (optional) + * @param callable|null $readDir (optional) + * @param callable|null $preClose (optional) + * @return resource|bool * - * @throws \BadMethodCallException */ public static function wrap($source, $read = null, $write = null, $close = null, $readDir = null, $preClose = null) { - $context = stream_context_create(array( - 'callback' => array( - 'source' => $source, - 'read' => $read, - 'write' => $write, - 'close' => $close, - 'readDir' => $readDir, - 'preClose' => $preClose, - ) - )); - return Wrapper::wrapSource($source, $context, 'callback', '\Icewind\Streams\CallbackWrapper'); + $context = [ + 'source' => $source, + 'read' => $read, + 'write' => $write, + 'close' => $close, + 'readDir' => $readDir, + 'preClose' => $preClose, + ]; + return self::wrapSource($source, $context); } protected function open() { - $context = $this->loadContext('callback'); + $context = $this->loadContext(); $this->readCallback = $context['read']; $this->writeCallback = $context['write']; @@ -112,7 +110,7 @@ class CallbackWrapper extends Wrapper { public function stream_close() { if (is_callable($this->preCloseCallback)) { - call_user_func($this->preCloseCallback, $this->loadContext('callback')['source']); + call_user_func($this->preCloseCallback, $this->source); // prevent further calls by potential PHP 7 GC ghosts $this->preCloseCallback = null; } diff --git a/apps/files_external/3rdparty/icewind/streams/src/CountWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/CountWrapper.php index 8b86ab9187..b3346209ae 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/CountWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/CountWrapper.php @@ -55,7 +55,7 @@ class CountWrapper extends Wrapper { * * @param resource $source * @param callable $callback - * @return resource + * @return resource|bool * * @throws \BadMethodCallException */ @@ -63,17 +63,14 @@ class CountWrapper extends Wrapper { if (!is_callable($callback)) { throw new \InvalidArgumentException('Invalid or missing callback'); } - $context = stream_context_create(array( - 'count' => array( - 'source' => $source, - 'callback' => $callback - ) - )); - return Wrapper::wrapSource($source, $context, 'callback', '\Icewind\Streams\CountWrapper'); + return self::wrapSource($source, [ + 'source' => $source, + 'callback' => $callback + ]); } protected function open() { - $context = $this->loadContext('count'); + $context = $this->loadContext(); $this->callback = $context['callback']; return true; } diff --git a/apps/files_external/3rdparty/icewind/streams/src/Directory.php b/apps/files_external/3rdparty/icewind/streams/src/Directory.php index c80a878386..912be76acf 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/Directory.php +++ b/apps/files_external/3rdparty/icewind/streams/src/Directory.php @@ -19,7 +19,7 @@ interface Directory { public function dir_opendir($path, $options); /** - * @return string + * @return string|bool */ public function dir_readdir(); diff --git a/apps/files_external/3rdparty/icewind/streams/src/DirectoryFilter.php b/apps/files_external/3rdparty/icewind/streams/src/DirectoryFilter.php index 4b86969900..80b27e8bab 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/DirectoryFilter.php +++ b/apps/files_external/3rdparty/icewind/streams/src/DirectoryFilter.php @@ -25,7 +25,7 @@ class DirectoryFilter extends DirectoryWrapper { * @return bool */ public function dir_opendir($path, $options) { - $context = $this->loadContext('filter'); + $context = $this->loadContext(); $this->filter = $context['filter']; return true; } @@ -36,7 +36,7 @@ class DirectoryFilter extends DirectoryWrapper { public function dir_readdir() { $file = readdir($this->source); $filter = $this->filter; - // keep reading untill we have an accepted entry or we're at the end of the folder + // keep reading until we have an accepted entry or we're at the end of the folder while ($file !== false && $filter($file) === false) { $file = readdir($this->source); } @@ -46,15 +46,12 @@ class DirectoryFilter extends DirectoryWrapper { /** * @param resource $source * @param callable $filter - * @return resource + * @return resource|bool */ public static function wrap($source, callable $filter) { - $options = array( - 'filter' => array( - 'source' => $source, - 'filter' => $filter - ) - ); - return self::wrapWithOptions($options, '\Icewind\Streams\DirectoryFilter'); + return self::wrapSource($source, [ + 'source' => $source, + 'filter' => $filter + ]); } } diff --git a/apps/files_external/3rdparty/icewind/streams/src/DirectoryWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/DirectoryWrapper.php index 63e4805a80..7f2f5c291c 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/DirectoryWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/DirectoryWrapper.php @@ -7,37 +7,9 @@ namespace Icewind\Streams; -class DirectoryWrapper implements Directory { - /** - * @var resource - */ - public $context; - - /** - * @var resource - */ - protected $source; - - /** - * Load the source from the stream context and return the context options - * - * @param string $name - * @return array - * @throws \Exception - */ - protected function loadContext($name) { - $context = stream_context_get_options($this->context); - if (isset($context[$name])) { - $context = $context[$name]; - } else { - throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set'); - } - if (isset($context['source']) and is_resource($context['source'])) { - $this->source = $context['source']; - } else { - throw new \BadMethodCallException('Invalid context, source not set'); - } - return $context; +class DirectoryWrapper extends Wrapper implements Directory { + public function stream_open($path, $mode, $options, &$opened_path) { + return false; } /** @@ -46,7 +18,7 @@ class DirectoryWrapper implements Directory { * @return bool */ public function dir_opendir($path, $options) { - $this->loadContext('dir'); + $this->loadContext(); return true; } @@ -72,17 +44,4 @@ class DirectoryWrapper implements Directory { rewinddir($this->source); return true; } - - /** - * @param array $options the options for the context to wrap the stream with - * @param string $class - * @return resource - */ - protected static function wrapWithOptions($options, $class) { - $context = stream_context_create($options); - stream_wrapper_register('dirwrapper', $class); - $wrapped = opendir('dirwrapper://', $context); - stream_wrapper_unregister('dirwrapper'); - return $wrapped; - } } diff --git a/apps/files_external/3rdparty/icewind/streams/src/File.php b/apps/files_external/3rdparty/icewind/streams/src/File.php index 252b7b8971..9662414a79 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/File.php +++ b/apps/files_external/3rdparty/icewind/streams/src/File.php @@ -15,7 +15,7 @@ interface File { * @param string $path * @param string $mode * @param int $options - * @param string &$opened_path + * @param string $opened_path * @return bool */ public function stream_open($path, $mode, $options, &$opened_path); @@ -28,19 +28,19 @@ interface File { public function stream_seek($offset, $whence = SEEK_SET); /** - * @return int + * @return int|false */ public function stream_tell(); /** * @param int $count - * @return string + * @return string|false */ public function stream_read($count); /** * @param string $data - * @return int + * @return int|false */ public function stream_write($data); @@ -59,7 +59,7 @@ interface File { public function stream_truncate($size); /** - * @return array + * @return array|false */ public function stream_stat(); diff --git a/apps/files_external/3rdparty/icewind/streams/src/HashWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/HashWrapper.php new file mode 100644 index 0000000000..616c2fe506 --- /dev/null +++ b/apps/files_external/3rdparty/icewind/streams/src/HashWrapper.php @@ -0,0 +1,78 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace Icewind\Streams; + +abstract class HashWrapper extends Wrapper { + + /** + * @var callable|null + */ + private $callback; + + /** + * @var resource|\HashContext + */ + private $hashContext; + + /** + * Wraps a stream to make it seekable + * + * @param resource $source + * @param string $hash + * @param callable $callback + * @return resource|bool + * + * @throws \BadMethodCallException + */ + public static function wrap($source, $hash, $callback) { + $context = [ + 'hash' => $hash, + 'callback' => $callback, + ]; + return self::wrapSource($source, $context); + } + + public function dir_opendir($path, $options) { + return false; + } + + public function stream_open($path, $mode, $options, &$opened_path) { + $context = $this->loadContext(); + $this->callback = $context['callback']; + $this->hashContext = hash_init($context['hash']); + return true; + } + + protected function updateHash($data) { + hash_update($this->hashContext, $data); + } + + public function stream_close() { + $hash = hash_final($this->hashContext); + if ($this->hashContext !== false && is_callable($this->callback)) { + call_user_func($this->callback, $hash); + } + return parent::stream_close(); + } +} diff --git a/apps/files_external/3rdparty/icewind/streams/src/IteratorDirectory.php b/apps/files_external/3rdparty/icewind/streams/src/IteratorDirectory.php index 6dfa42a8b6..a3872ddf47 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/IteratorDirectory.php +++ b/apps/files_external/3rdparty/icewind/streams/src/IteratorDirectory.php @@ -20,7 +20,7 @@ namespace Icewind\Streams; * * Either 'array' or 'iterator' need to be set, if both are set, 'iterator' takes preference */ -class IteratorDirectory implements Directory { +class IteratorDirectory extends WrapperHandler implements Directory { /** * @var resource */ @@ -36,18 +36,13 @@ class IteratorDirectory implements Directory { * * @param string $name * @return array - * @throws \Exception + * @throws \BadMethodCallException */ - protected function loadContext($name) { - $context = stream_context_get_options($this->context); - if (isset($context[$name])) { - $context = $context[$name]; - } else { - throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set'); - } + protected function loadContext($name = null) { + $context = parent::loadContext($name); if (isset($context['iterator'])) { $this->iterator = $context['iterator']; - } else if (isset($context['array'])) { + } elseif (isset($context['array'])) { $this->iterator = new \ArrayIterator($context['array']); } else { throw new \BadMethodCallException('Invalid context, iterator or array not set'); @@ -61,12 +56,12 @@ class IteratorDirectory implements Directory { * @return bool */ public function dir_opendir($path, $options) { - $this->loadContext('dir'); + $this->loadContext(); return true; } /** - * @return string + * @return string|bool */ public function dir_readdir() { if ($this->iterator->valid()) { @@ -97,27 +92,22 @@ class IteratorDirectory implements Directory { * Creates a directory handle from the provided array or iterator * * @param \Iterator | array $source - * @return resource + * @return resource|bool * * @throws \BadMethodCallException */ public static function wrap($source) { if ($source instanceof \Iterator) { - $context = stream_context_create(array( - 'dir' => array( - 'iterator' => $source) - )); - } else if (is_array($source)) { - $context = stream_context_create(array( - 'dir' => array( - 'array' => $source) - )); + $options = [ + 'iterator' => $source + ]; + } elseif (is_array($source)) { + $options = [ + 'array' => $source + ]; } else { throw new \BadMethodCallException('$source should be an Iterator or array'); } - stream_wrapper_register('iterator', '\Icewind\Streams\IteratorDirectory'); - $wrapped = opendir('iterator://', $context); - stream_wrapper_unregister('iterator'); - return $wrapped; + return self::wrapSource(self::NO_SOURCE_DIR, $options); } } diff --git a/apps/files_external/3rdparty/icewind/streams/src/NullWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/NullWrapper.php index b6c71d98fc..92aef2c7a2 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/NullWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/NullWrapper.php @@ -11,29 +11,17 @@ namespace Icewind\Streams; * Stream wrapper that does nothing, used for tests */ class NullWrapper extends Wrapper { - /** - * Wraps a stream with the provided callbacks - * - * @param resource $source - * @return resource - * - * @throws \BadMethodCallException - */ public static function wrap($source) { - $context = stream_context_create(array( - 'null' => array( - 'source' => $source) - )); - return Wrapper::wrapSource($source, $context, 'null', '\Icewind\Streams\NullWrapper'); + return self::wrapSource($source); } public function stream_open($path, $mode, $options, &$opened_path) { - $this->loadContext('null'); + $this->loadContext(); return true; } public function dir_opendir($path, $options) { - $this->loadContext('null'); + $this->loadContext(); return true; } } diff --git a/apps/files_external/3rdparty/icewind/streams/src/Path.php b/apps/files_external/3rdparty/icewind/streams/src/Path.php index bef9fd5f61..42d74a2ac1 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/Path.php +++ b/apps/files_external/3rdparty/icewind/streams/src/Path.php @@ -38,7 +38,7 @@ class Path { * @param string $class * @param array $contextOptions */ - public function __construct($class, $contextOptions = array()) { + public function __construct($class, $contextOptions = []) { $this->class = $class; $this->contextOptions = $contextOptions; } @@ -75,7 +75,7 @@ class Path { */ protected function appendDefaultContent($values) { if (!is_array(current($values))) { - $values = array($this->getProtocol() => $values); + $values = [$this->getProtocol() => $values]; } $context = stream_context_get_default(); $defaults = stream_context_get_options($context); diff --git a/apps/files_external/3rdparty/icewind/streams/src/PathWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/PathWrapper.php index 88af7e17b3..d9f3014c38 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/PathWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/PathWrapper.php @@ -16,10 +16,8 @@ class PathWrapper extends NullWrapper { * @return Path|string */ public static function getPath($source) { - return new Path(__CLASS__, [ - 'null' => [ - 'source' => $source - ] + return new Path(NullWrapper::class, [ + NullWrapper::getProtocol() => ['source' => $source] ]); } } diff --git a/apps/files_external/3rdparty/icewind/streams/src/ReadHashWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/ReadHashWrapper.php new file mode 100644 index 0000000000..16cf006ccf --- /dev/null +++ b/apps/files_external/3rdparty/icewind/streams/src/ReadHashWrapper.php @@ -0,0 +1,40 @@ + + * + * @author Roeland Jago Douma + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace Icewind\Streams; + +/** + * Wrapper that calculates the hash on the stream on read + * + * The stream and hash should be passed in when wrapping the stream. + * On close the callback will be called with the calculated checksum. + * + * For supported hashes see: http://php.net/manual/en/function.hash-algos.php + */ +class ReadHashWrapper extends HashWrapper { + public function stream_read($count) { + $data = parent::stream_read($count); + $this->updateHash($data); + return $data; + } +} diff --git a/apps/files_external/3rdparty/icewind/streams/src/RetryWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/RetryWrapper.php index 8238f19f7c..d4727aa96c 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/RetryWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/RetryWrapper.php @@ -11,25 +11,8 @@ namespace Icewind\Streams; * Wrapper that retries reads/writes to remote streams that dont deliver/recieve all requested data at once */ class RetryWrapper extends Wrapper { - - /** - * Wraps a stream with the provided callbacks - * - * @param resource $source - * @return resource - */ public static function wrap($source) { - $context = stream_context_create(array( - 'retry' => array( - 'source' => $source - ) - )); - return Wrapper::wrapSource($source, $context, 'retry', '\Icewind\Streams\RetryWrapper'); - } - - protected function open() { - $this->loadContext('retry'); - return true; + return self::wrapSource($source); } public function dir_opendir($path, $options) { @@ -37,7 +20,8 @@ class RetryWrapper extends Wrapper { } public function stream_open($path, $mode, $options, &$opened_path) { - return $this->open(); + $this->loadContext(); + return true; } public function stream_read($count) { diff --git a/apps/files_external/3rdparty/icewind/streams/src/SeekableWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/SeekableWrapper.php index d41fd73ec9..f131e75308 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/SeekableWrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/SeekableWrapper.php @@ -25,21 +25,8 @@ class SeekableWrapper extends Wrapper { */ protected $cache; - /** - * Wraps a stream to make it seekable - * - * @param resource $source - * @return resource - * - * @throws \BadMethodCallException - */ public static function wrap($source) { - $context = stream_context_create(array( - 'callback' => array( - 'source' => $source - ) - )); - return Wrapper::wrapSource($source, $context, 'callback', '\Icewind\Streams\SeekableWrapper'); + return self::wrapSource($source); } public function dir_opendir($path, $options) { @@ -47,8 +34,12 @@ class SeekableWrapper extends Wrapper { } public function stream_open($path, $mode, $options, &$opened_path) { - $this->loadContext('callback'); - $this->cache = fopen('php://temp', 'w+'); + $this->loadContext(); + $cache = fopen('php://temp', 'w+'); + if ($cache === false) { + return false; + } + $this->cache = $cache; return true; } @@ -72,7 +63,7 @@ class SeekableWrapper extends Wrapper { public function stream_seek($offset, $whence = SEEK_SET) { if ($whence === SEEK_SET) { $target = $offset; - } else if ($whence === SEEK_CUR) { + } elseif ($whence === SEEK_CUR) { $current = ftell($this->cache); $target = $current + $offset; } else { diff --git a/apps/files_external/3rdparty/icewind/streams/src/Url.php b/apps/files_external/3rdparty/icewind/streams/src/Url.php index d6822608a3..38cbbdd89b 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/Url.php +++ b/apps/files_external/3rdparty/icewind/streams/src/Url.php @@ -22,7 +22,7 @@ interface Url { * @param string $path * @param string $mode * @param int $options - * @param string &$opened_path + * @param string $opened_path * @return bool */ public function stream_open($path, $mode, $options, &$opened_path); @@ -50,7 +50,7 @@ interface Url { public function rmdir($path, $options); /** - * @param string + * @param string $path * @return bool */ public function unlink($path); @@ -58,7 +58,7 @@ interface Url { /** * @param string $path * @param int $flags - * @return array + * @return array|false */ public function url_stat($path, $flags); } diff --git a/apps/files_external/3rdparty/icewind/streams/src/UrlCallBack.php b/apps/files_external/3rdparty/icewind/streams/src/UrlCallback.php similarity index 69% rename from apps/files_external/3rdparty/icewind/streams/src/UrlCallBack.php rename to apps/files_external/3rdparty/icewind/streams/src/UrlCallback.php index 580bfc6ba2..09ba2aefee 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/UrlCallBack.php +++ b/apps/files_external/3rdparty/icewind/streams/src/UrlCallback.php @@ -47,24 +47,30 @@ class UrlCallback extends Wrapper implements Url { * @return \Icewind\Streams\Path * * @throws \BadMethodCallException - * @throws \Exception */ - public static function wrap($source, $fopen = null, $opendir = null, $mkdir = null, $rename = null, $rmdir = null, - $unlink = null, $stat = null) { - $options = array( - 'source' => $source, - 'fopen' => $fopen, + public static function wrap( + $source, + $fopen = null, + $opendir = null, + $mkdir = null, + $rename = null, + $rmdir = null, + $unlink = null, + $stat = null + ) { + return new Path(static::class, [ + 'source' => $source, + 'fopen' => $fopen, 'opendir' => $opendir, - 'mkdir' => $mkdir, - 'rename' => $rename, - 'rmdir' => $rmdir, - 'unlink' => $unlink, - 'stat' => $stat - ); - return new Path('\Icewind\Streams\UrlCallBack', $options); + 'mkdir' => $mkdir, + 'rename' => $rename, + 'rmdir' => $rmdir, + 'unlink' => $unlink, + 'stat' => $stat + ]); } - protected function loadContext($url) { + protected function loadUrlContext($url) { list($protocol) = explode('://', $url); $options = stream_context_get_options($this->context); return $options[$protocol]; @@ -77,40 +83,48 @@ class UrlCallback extends Wrapper implements Url { } public function stream_open($path, $mode, $options, &$opened_path) { - $context = $this->loadContext($path); + $context = $this->loadUrlContext($path); $this->callCallBack($context, 'fopen'); - $this->setSourceStream(fopen($context['source'], $mode)); + $source = fopen($context['source'], $mode); + if ($source === false) { + return false; + } + $this->setSourceStream($source); return true; } public function dir_opendir($path, $options) { - $context = $this->loadContext($path); + $context = $this->loadUrlContext($path); $this->callCallBack($context, 'opendir'); - $this->setSourceStream(opendir($context['source'])); + $source = opendir($context['source']); + if ($source === false) { + return false; + } + $this->setSourceStream($source); return true; } public function mkdir($path, $mode, $options) { - $context = $this->loadContext($path); + $context = $this->loadUrlContext($path); $this->callCallBack($context, 'mkdir'); - return mkdir($context['source'], $mode, $options & STREAM_MKDIR_RECURSIVE); + return mkdir($context['source'], $mode, ($options & STREAM_MKDIR_RECURSIVE) > 0); } public function rmdir($path, $options) { - $context = $this->loadContext($path); + $context = $this->loadUrlContext($path); $this->callCallBack($context, 'rmdir'); return rmdir($context['source']); } public function rename($source, $target) { - $context = $this->loadContext($source); + $context = $this->loadUrlContext($source); $this->callCallBack($context, 'rename'); list(, $target) = explode('://', $target); return rename($context['source'], $target); } public function unlink($path) { - $context = $this->loadContext($path); + $context = $this->loadUrlContext($path); $this->callCallBack($context, 'unlink'); return unlink($context['source']); } diff --git a/apps/files_external/3rdparty/icewind/streams/src/Wrapper.php b/apps/files_external/3rdparty/icewind/streams/src/Wrapper.php index babd2c1a0b..5dc8b29e77 100644 --- a/apps/files_external/3rdparty/icewind/streams/src/Wrapper.php +++ b/apps/files_external/3rdparty/icewind/streams/src/Wrapper.php @@ -12,7 +12,7 @@ namespace Icewind\Streams; * * This wrapper itself doesn't implement any functionality but is just a base class for other wrappers to extend */ -abstract class Wrapper implements File, Directory { +abstract class Wrapper extends WrapperHandler implements File, Directory { /** * @var resource */ @@ -25,44 +25,15 @@ abstract class Wrapper implements File, Directory { */ protected $source; - protected static function wrapSource($source, $context, $protocol, $class) { - if (!is_resource($source)) { - throw new \BadMethodCallException(); - } - try { - stream_wrapper_register($protocol, $class); - if (self::isDirectoryHandle($source)) { - $wrapped = opendir($protocol . '://', $context); - } else { - $wrapped = fopen($protocol . '://', 'r+', false, $context); - } - } catch (\BadMethodCallException $e) { - stream_wrapper_unregister($protocol); - throw $e; - } - stream_wrapper_unregister($protocol); - return $wrapped; - } - - protected static function isDirectoryHandle($resource) { - $meta = stream_get_meta_data($resource); - return $meta['stream_type'] == 'dir'; - } - /** - * Load the source from the stream context and return the context options - * - * @param string $name - * @return array - * @throws \Exception + * @param resource $source */ - protected function loadContext($name) { - $context = stream_context_get_options($this->context); - if (isset($context[$name])) { - $context = $context[$name]; - } else { - throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set'); - } + protected function setSourceStream($source) { + $this->source = $source; + } + + protected function loadContext($name = null) { + $context = parent::loadContext($name); if (isset($context['source']) and is_resource($context['source'])) { $this->setSourceStream($context['source']); } else { @@ -71,13 +42,6 @@ abstract class Wrapper implements File, Directory { return $context; } - /** - * @param resource $source - */ - protected function setSourceStream($source) { - $this->source = $source; - } - public function stream_seek($offset, $whence = SEEK_SET) { $result = fseek($this->source, $offset, $whence); return $result == 0 ? true : false; @@ -98,14 +62,13 @@ abstract class Wrapper implements File, Directory { public function stream_set_option($option, $arg1, $arg2) { switch ($option) { case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; + return stream_set_blocking($this->source, (bool)$arg1); case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; + return stream_set_timeout($this->source, $arg1, $arg2); case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1); + return stream_set_write_buffer($this->source, $arg1) === 0; } + return false; } public function stream_truncate($size) { diff --git a/apps/files_external/3rdparty/icewind/streams/src/WrapperHandler.php b/apps/files_external/3rdparty/icewind/streams/src/WrapperHandler.php new file mode 100644 index 0000000000..52a02feb19 --- /dev/null +++ b/apps/files_external/3rdparty/icewind/streams/src/WrapperHandler.php @@ -0,0 +1,114 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace Icewind\Streams; + +class WrapperHandler { + /** @var resource $context */ + protected $context; + + const NO_SOURCE_DIR = 1; + + /** + * get the protocol name that is generated for the class + * @param string|null $class + * @return string + */ + public static function getProtocol($class = null) { + if ($class === null) { + $class = static::class; + } + + $parts = explode('\\', $class); + return strtolower(array_pop($parts)); + } + + private static function buildContext($protocol, $context, $source) { + if (is_array($context)) { + $context['source'] = $source; + return stream_context_create([$protocol => $context]); + } else { + return $context; + } + } + + /** + * @param resource|int $source + * @param resource|array $context + * @param string|null $protocol deprecated, protocol is now automatically generated + * @param string|null $class deprecated, class is now automatically generated + * @return bool|resource + */ + protected static function wrapSource($source, $context = [], $protocol = null, $class = null) { + if ($class === null) { + $class = static::class; + } + + if ($protocol === null) { + $protocol = self::getProtocol($class); + } + + $context = self::buildContext($protocol, $context, $source); + try { + stream_wrapper_register($protocol, $class); + if (self::isDirectoryHandle($source)) { + return opendir($protocol . '://', $context); + } else { + return fopen($protocol . '://', 'r+', false, $context); + } + } finally { + stream_wrapper_unregister($protocol); + } + } + + protected static function isDirectoryHandle($resource) { + if ($resource === self::NO_SOURCE_DIR) { + return true; + } + if (!is_resource($resource)) { + throw new \BadMethodCallException('Invalid stream source'); + } + $meta = stream_get_meta_data($resource); + return $meta['stream_type'] === 'dir' || $meta['stream_type'] === 'user-space-dir'; + } + + /** + * Load the source from the stream context and return the context options + * + * @param string|null $name if not set, the generated protocol name is used + * @return array + * @throws \BadMethodCallException + */ + protected function loadContext($name = null) { + if ($name === null) { + $parts = explode('\\', static::class); + $name = strtolower(array_pop($parts)); + } + + $context = stream_context_get_options($this->context); + if (isset($context[$name])) { + $context = $context[$name]; + } else { + throw new \BadMethodCallException('Invalid context, "' . $name . '" options not set'); + } + return $context; + } +} diff --git a/apps/files_external/3rdparty/icewind/streams/src/WriteHashWrapper.php b/apps/files_external/3rdparty/icewind/streams/src/WriteHashWrapper.php new file mode 100644 index 0000000000..279d9fd10e --- /dev/null +++ b/apps/files_external/3rdparty/icewind/streams/src/WriteHashWrapper.php @@ -0,0 +1,37 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace Icewind\Streams; + +/** + * Wrapper that calculates the hash on the stream on write + * + * The stream and hash should be passed in when wrapping the stream. + * On close the callback will be called with the calculated checksum. + * + * For supported hashes see: http://php.net/manual/en/function.hash-algos.php + */ +class WriteHashWrapper extends HashWrapper { + public function stream_write($data) { + $this->updateHash($data); + return parent::stream_write($data); + } +}