Browse Source

update icewind/smb to 3.5.1

Signed-off-by: Robin Appelman <robin@icewind.nl>
tags/v24.0.0beta1
Robin Appelman 2 years ago
parent
commit
a9619c3770
No account linked to committer's email address

+ 2
- 0
apps/files_external/3rdparty/.gitignore View File

@@ -5,6 +5,8 @@ icewind/smb/install_libsmbclient.sh
icewind/smb/Makefile
icewind/smb/.travis.yml
icewind/smb/.scrutinizer.yml
icewind/smb/example-apache-kerberos.php
icewind/smb/codecov.yml
icewind/streams/tests
.github
.php_cs*

+ 1
- 1
apps/files_external/3rdparty/composer.json View File

@@ -9,6 +9,6 @@
},
"require": {
"icewind/streams": "0.7.4",
"icewind/smb": "3.4.1"
"icewind/smb": "3.5.1"
}
}

+ 7
- 7
apps/files_external/3rdparty/composer.lock View File

@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0ffc772b2aaaaffe52decb8d13361976",
"content-hash": "ed821b15824934fd2d245faca1f35aad",
"packages": [
{
"name": "icewind/smb",
"version": "v3.4.1",
"version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3"
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
"shasum": ""
},
"require": {
@@ -49,9 +49,9 @@
"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.1"
"source": "https://github.com/icewind1991/SMB/tree/v3.5.1"
},
"time": "2021-04-19T13:53:08+00:00"
"time": "2021-11-04T14:28:18+00:00"
},
{
"name": "icewind/streams",

+ 102
- 11
apps/files_external/3rdparty/composer/ClassLoader.php View File

@@ -42,30 +42,75 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;

// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();

// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();

/** @var bool */
private $useIncludePath = false;

/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();

/** @var bool */
private $classMapAuthoritative = false;

/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();

/** @var ?string */
private $apcuPrefix;

/**
* @var self[]
*/
private static $registeredLoaders = array();

/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}

/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
@@ -75,28 +120,47 @@ class ClassLoader
return array();
}

/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}

/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}

/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}

/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}

/**
* @param array $classMap Class to filename map
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
@@ -111,9 +175,11 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
@@ -156,11 +222,13 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
@@ -204,8 +272,10 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
@@ -220,10 +290,12 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
@@ -243,6 +315,8 @@ class ClassLoader
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
@@ -265,6 +339,8 @@ class ClassLoader
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
@@ -285,6 +361,8 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
@@ -305,6 +383,8 @@ class ClassLoader
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
@@ -324,6 +404,8 @@ class ClassLoader

/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
@@ -403,6 +485,11 @@ class ClassLoader
return self::$registeredLoaders;
}

/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
@@ -474,6 +561,10 @@ class ClassLoader
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{

+ 19
- 6
apps/files_external/3rdparty/composer/InstalledVersions.php View File

@@ -20,12 +20,25 @@ use Composer\Semver\VersionParser;
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require it's presence, you can require `composer-runtime-api ^2.0`
* To require its presence, you can require `composer-runtime-api ^2.0`
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
*/
private static $installed;

/**
* @var bool|null
*/
private static $canGetVendors;

/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static $installedByVendor = array();

/**
@@ -228,7 +241,7 @@ class InstalledVersions

/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
@@ -242,7 +255,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@@ -265,7 +278,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
@@ -288,7 +301,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>} $data
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
@@ -298,7 +311,7 @@ class InstalledVersions

/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string}>}>
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{

+ 1
- 0
apps/files_external/3rdparty/composer/autoload_classmap.php View File

@@ -48,6 +48,7 @@ return array(
'Icewind\\SMB\\IShare' => $vendorDir . '/icewind/smb/src/IShare.php',
'Icewind\\SMB\\ISystem' => $vendorDir . '/icewind/smb/src/ISystem.php',
'Icewind\\SMB\\ITimeZoneProvider' => $vendorDir . '/icewind/smb/src/ITimeZoneProvider.php',
'Icewind\\SMB\\KerberosApacheAuth' => $vendorDir . '/icewind/smb/src/KerberosApacheAuth.php',
'Icewind\\SMB\\KerberosAuth' => $vendorDir . '/icewind/smb/src/KerberosAuth.php',
'Icewind\\SMB\\Native\\NativeFileInfo' => $vendorDir . '/icewind/smb/src/Native/NativeFileInfo.php',
'Icewind\\SMB\\Native\\NativeReadStream' => $vendorDir . '/icewind/smb/src/Native/NativeReadStream.php',

+ 1
- 0
apps/files_external/3rdparty/composer/autoload_static.php View File

@@ -68,6 +68,7 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3
'Icewind\\SMB\\IShare' => __DIR__ . '/..' . '/icewind/smb/src/IShare.php',
'Icewind\\SMB\\ISystem' => __DIR__ . '/..' . '/icewind/smb/src/ISystem.php',
'Icewind\\SMB\\ITimeZoneProvider' => __DIR__ . '/..' . '/icewind/smb/src/ITimeZoneProvider.php',
'Icewind\\SMB\\KerberosApacheAuth' => __DIR__ . '/..' . '/icewind/smb/src/KerberosApacheAuth.php',
'Icewind\\SMB\\KerberosAuth' => __DIR__ . '/..' . '/icewind/smb/src/KerberosAuth.php',
'Icewind\\SMB\\Native\\NativeFileInfo' => __DIR__ . '/..' . '/icewind/smb/src/Native/NativeFileInfo.php',
'Icewind\\SMB\\Native\\NativeReadStream' => __DIR__ . '/..' . '/icewind/smb/src/Native/NativeReadStream.php',

+ 7
- 7
apps/files_external/3rdparty/composer/installed.json View File

@@ -2,17 +2,17 @@
"packages": [
{
"name": "icewind/smb",
"version": "v3.4.1",
"version_normalized": "3.4.1.0",
"version": "v3.5.1",
"version_normalized": "3.5.1.0",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3"
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
"reference": "9dba42ab2a3990de29e18cc62b0a8270aceb74e3",
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
"reference": "c1ce4fbb2ff1786846d9d0b3850b395ca94cf563",
"shasum": ""
},
"require": {
@@ -25,7 +25,7 @@
"phpunit/phpunit": "^8.5|^9.3.8",
"psalm/phar": "^4.3"
},
"time": "2021-04-19T13:53:08+00:00",
"time": "2021-11-04T14:28:18+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -46,7 +46,7 @@
"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.1"
"source": "https://github.com/icewind1991/SMB/tree/v3.5.1"
},
"install-path": "../icewind/smb"
},

+ 5
- 5
apps/files_external/3rdparty/composer/installed.php View File

@@ -5,7 +5,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
'reference' => '70483a16a3a232758979bb6fa363629b5a16b6a4',
'reference' => 'cd72330b8f669e3dc81388be5a92171404f36fec',
'name' => 'files_external/3rdparty',
'dev' => true,
),
@@ -16,16 +16,16 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
'reference' => '70483a16a3a232758979bb6fa363629b5a16b6a4',
'reference' => 'cd72330b8f669e3dc81388be5a92171404f36fec',
'dev_requirement' => false,
),
'icewind/smb' => array(
'pretty_version' => 'v3.4.1',
'version' => '3.4.1.0',
'pretty_version' => 'v3.5.1',
'version' => '3.5.1.0',
'type' => 'library',
'install_path' => __DIR__ . '/../icewind/smb',
'aliases' => array(),
'reference' => '9dba42ab2a3990de29e18cc62b0a8270aceb74e3',
'reference' => 'c1ce4fbb2ff1786846d9d0b3850b395ca94cf563',
'dev_requirement' => false,
),
'icewind/streams' => array(

+ 30
- 1
apps/files_external/3rdparty/icewind/smb/README.md View File

@@ -44,13 +44,42 @@ $server = $serverFactory->createServer('localhost', $auth);

### Using kerberos authentication ###

There are two ways of using kerberos to authenticate against the smb server:

- Using a ticket from the php server
- Re-using a ticket send by the client

### Using a server ticket

Using a server ticket allows the web server to authenticate against the smb server using an existing machine account.

The ticket needs to be available in the environment of the php process.

```php
$serverFactory = new ServerFactory();
$auth = new KerberosAuth();
$server = $serverFactory->createServer('localhost', $auth);
```

Note that this requires a valid kerberos ticket to already be available for php
### Re-using a client ticket

By re-using a client ticket you can create a single sign-on setup where the user authenticates against
the web service using kerberos. And the web server can forward that ticket to the smb server, allowing it
to act on the behalf of the user without requiring the user to enter his passord.

The setup for such a system is fairly involved and requires roughly the following this

- The web server is authenticated against kerberos with a machine account
- Delegation is enabled for the web server's machine account
- Apache is setup to perform kerberos authentication and save the ticket in it's environment
- Php has the krb5 extension installed
- The client authenticates using a ticket with forwarding enabled

```php
$serverFactory = new ServerFactory();
$auth = new KerberosApacheAuth();
$server = $serverFactory->createServer('localhost', $auth);
```

### Upload a file ###


+ 1
- 1
apps/files_external/3rdparty/icewind/smb/src/IShare.php View File

@@ -45,7 +45,7 @@ interface IShare {
public function put(string $source, string $target): bool;

/**
* Open a readable stream top a remote file
* Open a readable stream to a remote file
*
* @param string $source
* @return resource a read only stream with the contents of the remote file

+ 117
- 0
apps/files_external/3rdparty/icewind/smb/src/KerberosApacheAuth.php View File

@@ -0,0 +1,117 @@
<?php
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/

namespace Icewind\SMB;

use Icewind\SMB\Exception\DependencyException;
use Icewind\SMB\Exception\Exception;

/**
* Use existing kerberos ticket to authenticate and reuse the apache ticket cache (mod_auth_kerb)
*/
class KerberosApacheAuth extends KerberosAuth implements IAuth {
/** @var string */
private $ticketPath = "";

// only working with specific library (mod_auth_kerb, krb5, smbclient) versions
/** @var bool */
private $saveTicketInMemory = false;

/** @var bool */
private $init = false;

/**
* @param bool $saveTicketInMemory
*/
public function __construct(bool $saveTicketInMemory = false) {
$this->saveTicketInMemory = $saveTicketInMemory;
}

/**
* Check if a valid kerberos ticket is present
*
* @return bool
*/
public function checkTicket(): bool {
//read apache kerberos ticket cache
$cacheFile = getenv("KRB5CCNAME");
if (!$cacheFile) {
return false;
}

$krb5 = new \KRB5CCache();
$krb5->open($cacheFile);
return (bool)$krb5->isValid();
}

private function init(): void {
if ($this->init) {
return;
}
$this->init = true;
// inspired by https://git.typo3.org/TYPO3CMS/Extensions/fal_cifs.git

if (!extension_loaded("krb5")) {
// https://pecl.php.net/package/krb5
throw new DependencyException('Ensure php-krb5 is installed.');
}

//read apache kerberos ticket cache
$cacheFile = getenv("KRB5CCNAME");
if (!$cacheFile) {
throw new Exception('No kerberos ticket cache environment variable (KRB5CCNAME) found.');
}

$krb5 = new \KRB5CCache();
$krb5->open($cacheFile);
if (!$krb5->isValid()) {
throw new Exception('Kerberos ticket cache is not valid.');
}


if ($this->saveTicketInMemory) {
putenv("KRB5CCNAME=" . (string)$krb5->getName());
} else {
//workaround: smbclient is not working with the original apache ticket cache.
$tmpFilename = tempnam("/tmp", "krb5cc_php_");
$tmpCacheFile = "FILE:" . $tmpFilename;
$krb5->save($tmpCacheFile);
$this->ticketPath = $tmpFilename;
putenv("KRB5CCNAME=" . $tmpCacheFile);
}
}

public function getExtraCommandLineArguments(): string {
$this->init();
return parent::getExtraCommandLineArguments();
}

public function setExtraSmbClientOptions($smbClientState): void {
$this->init();
parent::setExtraSmbClientOptions($smbClientState);
}

public function __destruct() {
if (!empty($this->ticketPath) && file_exists($this->ticketPath) && is_file($this->ticketPath)) {
unlink($this->ticketPath);
}
}
}

+ 1
- 1
apps/files_external/3rdparty/icewind/smb/src/Native/NativeFileInfo.php View File

@@ -99,7 +99,7 @@ class NativeFileInfo implements IFileInfo {
public function isDirectory(): bool {
$mode = $this->getMode();
if ($mode > 0x1000) {
return (bool)($mode & 0x4000); // 0x4000: unix directory flag
return ($mode & 0x4000 && !($mode & 0x8000)); // 0x4000: unix directory flag shares bits with 0xC000: socket
} else {
return (bool)($mode & IFileInfo::MODE_DIRECTORY);
}

+ 6
- 6
apps/files_external/3rdparty/icewind/smb/src/Native/NativeShare.php View File

@@ -267,14 +267,14 @@ class NativeShare extends AbstractShare {
* Open a writeable stream to a remote file
* Note: This method will truncate the file to 0bytes first
*
* @param string $source
* @param string $target
* @return resource a writeable stream
*
* @throws NotFoundException
* @throws InvalidTypeException
*/
public function write(string $source) {
$url = $this->buildUrl($source);
public function write(string $target) {
$url = $this->buildUrl($target);
$handle = $this->getState()->create($url);
return NativeWriteStream::wrap($this->getState(), $handle, 'w', $url);
}
@@ -282,14 +282,14 @@ class NativeShare extends AbstractShare {
/**
* Open a writeable stream and set the cursor to the end of the stream
*
* @param string $source
* @param string $target
* @return resource a writeable stream
*
* @throws NotFoundException
* @throws InvalidTypeException
*/
public function append(string $source) {
$url = $this->buildUrl($source);
public function append(string $target) {
$url = $this->buildUrl($target);
$handle = $this->getState()->open($url, "a+");
return NativeWriteStream::wrap($this->getState(), $handle, "a", $url);
}

+ 13
- 0
apps/files_external/3rdparty/icewind/smb/src/Native/NativeState.php View File

@@ -38,6 +38,14 @@ class NativeState {
/** @var bool */
protected $connected = false;

/**
* sync the garbage collection cycle
* __deconstruct() of KerberosAuth should not called too soon
*
* @var IAuth|null $auth
*/
protected $auth = null;

// see error.h
const EXCEPTION_MAP = [
1 => ForbiddenException::class,
@@ -107,6 +115,11 @@ class NativeState {
}

$auth->setExtraSmbClientOptions($this->state);

// sync the garbage collection cycle
// __deconstruct() of KerberosAuth should not caled too soon
$this->auth = $auth;

/** @var bool $result */
$result = @smbclient_state_init($this->state, $auth->getWorkgroup(), $auth->getUsername(), $auth->getPassword());


+ 1
- 1
apps/files_external/3rdparty/icewind/smb/src/System.php View File

@@ -62,7 +62,7 @@ class System implements ISystem {
$result = null;
$output = [];
exec("which $binary 2>&1", $output, $result);
$this->paths[$binary] = $result === 0 ? trim(implode('', $output)) : null;
$this->paths[$binary] = $result === 0 && isset($output[0]) ? (string)$output[0] : null;
}
return $this->paths[$binary];
}

+ 11
- 32
apps/files_external/3rdparty/icewind/smb/src/Wrapped/Connection.php View File

@@ -47,7 +47,7 @@ class Connection extends RawConnection {
public function clearTillPrompt(): void {
$this->write('');
do {
$promptLine = $this->readLine();
$promptLine = $this->readTillPrompt();
if ($promptLine === false) {
break;
}
@@ -56,13 +56,12 @@ class Connection extends RawConnection {
if ($this->write('') === false) {
throw new ConnectionRefusedException();
}
$this->readLine();
$this->readTillPrompt();
}

/**
* get all unprocessed output from smbclient until the next prompt
*
* @param (callable(string):bool)|null $callback (optional) callback to call for every line read
* @return string[]
* @throws AuthenticationException
* @throws ConnectException
@@ -71,42 +70,22 @@ class Connection extends RawConnection {
* @throws NoLoginServerException
* @throws AccessDeniedException
*/
public function read(callable $callback = null): array {
public function read(): 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 = [];
if (!$this->isPrompt($promptLine)) {
$line = $promptLine;
} else {
$line = $this->readLine();
}
if ($line === false) {
$this->unknownError($promptLine);
}
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
$this->close(true);
break;
}
} else {
$output[] = $line;
}
$line = $this->readLine();
$output = $this->readTillPrompt();
if ($output === false) {
$this->unknownError(false);
}
$output = explode("\n", $output);
// last line contains the prompt
array_pop($output);
return $output;
}

private function isPrompt(string $line): bool {
return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER;
return substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER;
}

/**
@@ -132,6 +111,6 @@ class Connection extends RawConnection {
// ignore any errors while trying to send the close command, the process might already be dead
@$this->write('close' . PHP_EOL);
}
parent::close($terminate);
$this->close_process($terminate);
}
}

+ 9
- 5
apps/files_external/3rdparty/icewind/smb/src/Wrapped/NotifyHandler.php View File

@@ -65,16 +65,20 @@ class NotifyHandler implements INotifyHandler {
*/
public function listen(callable $callback): void {
if ($this->listening) {
$this->connection->read(function (string $line) use ($callback): bool {
while (true) {
$line = $this->connection->readLine();
if ($line === false) {
break;
}
$this->checkForError($line);
$change = $this->parseChangeLine($line);
if ($change) {
$result = $callback($change);
return $result === false ? false : true;
} else {
return true;
if ($result === false) {
break;
}
}
});
};
}
}


+ 30
- 4
apps/files_external/3rdparty/icewind/smb/src/Wrapped/RawConnection.php View File

@@ -71,7 +71,8 @@ class RawConnection {

setlocale(LC_ALL, Server::LOCALE);
$env = array_merge($this->env, [
'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!!
'CLI_FORCE_INTERACTIVE' => 'y', // Make sure the prompt is displayed
'CLI_NO_READLINE' => 1, // Not all distros build smbclient with readline, disable it to get consistent behaviour
'LC_ALL' => Server::LOCALE,
'LANG' => Server::LOCALE,
'COLUMNS' => 8192 // prevent smbclient from line-wrapping it's output
@@ -91,7 +92,7 @@ class RawConnection {
public function isValid(): bool {
if (is_resource($this->process)) {
$status = proc_get_status($this->process);
return (bool)$status['running'];
return $status['running'];
} else {
return false;
}
@@ -109,13 +110,30 @@ class RawConnection {
return $result;
}

/**
* read output till the next prompt
*
* @return string|false
*/
public function readTillPrompt() {
$output = "";
do {
$chunk = $this->readLine('\> ');
if ($chunk === false) {
return false;
}
$output .= $chunk;
} while (strlen($chunk) == 4096 && strpos($chunk, "smb:") === false);
return $output;
}

/**
* read a line of output
*
* @return string|false
*/
public function readLine() {
return stream_get_line($this->getOutputStream(), 4086, "\n");
public function readLine(string $end = "\n") {
return stream_get_line($this->getOutputStream(), 4096, $end);
}

/**
@@ -202,6 +220,14 @@ class RawConnection {
* @psalm-assert null $this->process
*/
public function close(bool $terminate = true): void {
$this->close_process($terminate);
}

/**
* @param bool $terminate
* @psalm-assert null $this->process
*/
protected function close_process(bool $terminate = true): void {
if (!is_resource($this->process)) {
return;
}

+ 11
- 3
apps/files_external/3rdparty/icewind/smb/src/Wrapped/Share.php View File

@@ -345,11 +345,17 @@ class Share extends AbstractShare {
// 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
$connection = $this->getConnection();
stream_set_blocking($connection->getOutputStream(), false);

$connection->write('get ' . $source . ' ' . $this->system->getFD(5));
$connection->write('exit');
$fh = $connection->getFileOutputStream();
stream_context_set_option($fh, 'file', 'connection', $connection);
$fh = CallbackWrapper::wrap($fh, function() use ($connection) {
$connection->write('');
});
if (!is_resource($fh)) {
throw new Exception("Failed to wrap file output");
}
return $fh;
}

@@ -374,7 +380,9 @@ 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
$stream = CallbackWrapper::wrap($fh, null, null, function () use ($connection) {
$stream = CallbackWrapper::wrap($fh, function() use ($connection) {
$connection->write('');
}, null, function () use ($connection) {
$connection->close(false); // dont terminate, give the upload some time
});
if (is_resource($stream)) {
@@ -446,7 +454,7 @@ class Share extends AbstractShare {
* @return string[]
*/
protected function execute(string $command): array {
$this->connect()->write($command . PHP_EOL);
$this->connect()->write($command);
return $this->connect()->read();
}


Loading…
Cancel
Save