diff options
author | Robin Appelman <robin@icewind.nl> | 2021-03-10 15:31:09 +0100 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2021-03-10 15:31:09 +0100 |
commit | 66781e74ada3fd22bb5b246a59897ac146cda4dd (patch) | |
tree | ddb35b074eb6523c1aaffb68e78f58faf797ae23 /apps/files_external/3rdparty/icewind/smb/src | |
parent | 62929cc646134fbd409cfb4eacb7039d15763b96 (diff) | |
download | nextcloud-server-66781e74ada3fd22bb5b246a59897ac146cda4dd.tar.gz nextcloud-server-66781e74ada3fd22bb5b246a59897ac146cda4dd.zip |
update icewind/smb to 3.4.0
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'apps/files_external/3rdparty/icewind/smb/src')
37 files changed, 907 insertions, 760 deletions
diff --git a/apps/files_external/3rdparty/icewind/smb/src/ACL.php b/apps/files_external/3rdparty/icewind/smb/src/ACL.php index bdb77257f17..0b5b05a86af 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 aa2adfa67b3..810ca807d9b 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 b53c253be08..454eb143e49 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 737cc7c63f1..0f3524002be 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 9d7f9b5d306..04004e6ebd8 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 9dfd57b3973..4d6ab49d2bb 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 4954518f980..e3e860b30d5 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<int|string, class-string<Exception>> $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 882bf1677bf..1494de9efcb 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 e898b5a2347..3c7c180bf93 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 731b315ebaa..9d4302dd4e8 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 3411d498d78..7e440c1420b 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 c3ee3ffe8cf..e964a15fa37 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 c46d2c8b3dc..4ab7b26c660 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 0b832025aab..c2f5a504bcf 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 d33d10bb3fb..6ac6e0d2d15 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 09994610716..6f06b8421c2 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 56e09ffb392..d624bcec854 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 0e91202cb76..7cd9258465a 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 d8be57c7311..539bb728426 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 fe0af760d3f..f39ec4db392 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 aadb05d0fea..68b6c46ca2f 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 5368538edca..03ec501b830 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 3bfb1c3da24..10ba6ce0458 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 c75afaa5f1d..216c27f78e3 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<NativeStream> $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 4e90e5a655d..7c27499764c 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 7a0d0149b73..f590594b993 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 807b0b872cf..4c579d06843 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 00000000000..85661218760 --- /dev/null +++ b/apps/files_external/3rdparty/icewind/smb/src/StringBuffer.php @@ -0,0 +1,63 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2021 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; + +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 0e41ee032d6..919907477ab 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 7ae049c406f..4cd3b65681c 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 347b63db110..31b72b05d97 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<string, string> $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 a310a6bc913..de5a696df7b 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 090734381bb..18451f4daa6 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 a28432e4319..ec14ac4b1fb 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<string, string> + */ + 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 3a114af5e4f..26a17cc584b 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<string, string> $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 b3763a73245..60cc9278dd9 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 ea386a87bfc..68446d380e0 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 { |