diff options
author | Robin Appelman <robin@icewind.nl> | 2016-12-14 16:22:33 +0100 |
---|---|---|
committer | Roeland Jago Douma <roeland@famdouma.nl> | 2017-01-05 09:16:03 +0100 |
commit | 84296877888ff901c1bc5a9264d44ffb915e7c56 (patch) | |
tree | ce62009cd10f98987606921ec3945160c0de1634 /apps/files_external/3rdparty/icewind | |
parent | 6a0f0403d01dc6a889157b446edef73f9af58540 (diff) | |
download | nextcloud-server-84296877888ff901c1bc5a9264d44ffb915e7c56.tar.gz nextcloud-server-84296877888ff901c1bc5a9264d44ffb915e7c56.zip |
Update icewind/smb to 2.0.0
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'apps/files_external/3rdparty/icewind')
14 files changed, 239 insertions, 240 deletions
diff --git a/apps/files_external/3rdparty/icewind/smb/README.md b/apps/files_external/3rdparty/icewind/smb/README.md index 32f3c650f87..c8f31193c83 100644 --- a/apps/files_external/3rdparty/icewind/smb/README.md +++ b/apps/files_external/3rdparty/icewind/smb/README.md @@ -1,7 +1,7 @@ SMB === -[![Coverage Status](https://img.shields.io/coveralls/icewind1991/SMB.svg)](https://coveralls.io/r/icewind1991/SMB?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/icewind1991/SMB/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/icewind1991/SMB/?branch=master) [![Build Status](https://travis-ci.org/icewind1991/SMB.svg?branch=master)](https://travis-ci.org/icewind1991/SMB) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/icewind1991/SMB/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/icewind1991/SMB/?branch=master) @@ -134,3 +134,19 @@ if (Server::NativeAvailable()) { $share = $server->getShare('test'); $share->put($fileToUpload, 'example.txt'); ``` + +### Using notify + +```php +<?php +use Icewind\SMB\Server; + +require('vendor/autoload.php'); + +$server = new Server('localhost', 'test', 'test'); +$share = $server->getShare('test'); + +$share->notify('')->listen(function (\Icewind\SMB\Change $change) { + echo $change->getCode() . ': ' . $change->getPath() . "\n"; +}); +``` diff --git a/apps/files_external/3rdparty/icewind/smb/composer.json b/apps/files_external/3rdparty/icewind/smb/composer.json index 4ac8b27e725..8374f564bf1 100644 --- a/apps/files_external/3rdparty/icewind/smb/composer.json +++ b/apps/files_external/3rdparty/icewind/smb/composer.json @@ -9,11 +9,10 @@ } ], "require" : { - "php": ">=5.3", + "php": ">=5.4", "icewind/streams": ">=0.2.0" }, "require-dev": { - "satooshi/php-coveralls" : "v1.0.0", "phpunit/phpunit": "^4.8" }, "autoload" : { diff --git a/apps/files_external/3rdparty/icewind/smb/src/Connection.php b/apps/files_external/3rdparty/icewind/smb/src/Connection.php index d24cdc1f6d0..c1ebb861711 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Connection.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Connection.php @@ -17,6 +17,14 @@ class Connection extends RawConnection { const DELIMITER = 'smb:'; const DELIMITER_LENGTH = 4; + /** @var Parser */ + private $parser; + + public function __construct($command, Parser $parser, $env = array()) { + parent::__construct($command, $env); + $this->parser = $parser; + } + /** * send input to smbclient * @@ -30,7 +38,7 @@ class Connection extends RawConnection { * get all unprocessed output from smbclient until the next prompt * * @param callable $callback (optional) callback to call for every line read - * @return string + * @return string[] * @throws AuthenticationException * @throws ConnectException * @throws ConnectionException @@ -42,7 +50,7 @@ class Connection extends RawConnection { throw new ConnectionException('Connection not valid'); } $promptLine = $this->readLine(); //first line is prompt - $this->checkConnectionError($promptLine); + $this->parser->checkConnectionError($promptLine); $output = array(); $line = $this->readLine(); @@ -54,6 +62,7 @@ class Connection extends RawConnection { $result = $callback($line); if ($result === false) { // allow the callback to close the connection for infinite running commands $this->close(true); + break; } } else { $output[] .= $line; @@ -90,33 +99,6 @@ class Connection extends RawConnection { } } - /** - * check if the first line holds a connection failure - * - * @param $line - * @throws AuthenticationException - * @throws InvalidHostException - * @throws NoLoginServerException - */ - private function checkConnectionError($line) { - $line = rtrim($line, ')'); - if (substr($line, -23) === ErrorCodes::LogonFailure) { - throw new AuthenticationException('Invalid login'); - } - if (substr($line, -26) === ErrorCodes::BadHostName) { - throw new InvalidHostException('Invalid hostname'); - } - if (substr($line, -22) === ErrorCodes::Unsuccessful) { - throw new InvalidHostException('Connection unsuccessful'); - } - if (substr($line, -28) === ErrorCodes::ConnectionRefused) { - throw new InvalidHostException('Connection refused'); - } - if (substr($line, -26) === ErrorCodes::NoLogonServers) { - throw new NoLoginServerException('No login server'); - } - } - public function close($terminate = true) { if (is_resource($this->getInputStream())) { $this->write('close' . PHP_EOL); 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 3307ad57a24..7ac528198a9 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php @@ -7,4 +7,32 @@ namespace Icewind\SMB\Exception; -class Exception extends \Exception {} +class Exception extends \Exception { + static public function unknown($path, $error) { + $message = 'Unknown error (' . $error . ')'; + if ($path) { + $message .= ' for ' . $path; + } + + return new Exception($message, $error); + } + + /** + * @param array $exceptionMap + * @param mixed $error + * @param string $path + * @return Exception + */ + static public function fromMap(array $exceptionMap, $error, $path) { + if (isset($exceptionMap[$error])) { + $exceptionClass = $exceptionMap[$error]; + if (is_numeric($error)) { + return new $exceptionClass($path, $error); + } else { + return new $exceptionClass($path); + } + } else { + return Exception::unknown($path, $error); + } + } +} diff --git a/apps/files_external/3rdparty/icewind/smb/src/IShare.php b/apps/files_external/3rdparty/icewind/smb/src/IShare.php index 40423151332..8f6d5058b81 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IShare.php @@ -8,17 +8,6 @@ namespace Icewind\SMB; interface IShare { - // https://msdn.microsoft.com/en-us/library/dn392331.aspx - const NOTIFY_ADDED = 1; - const NOTIFY_REMOVED = 2; - const NOTIFY_MODIFIED = 3; - const NOTIFY_RENAMED_OLD = 4; - const NOTIFY_RENAMED_NEW = 5; - const NOTIFY_ADDED_STREAM = 6; - const NOTIFY_REMOVED_STREAM = 7; - const NOTIFY_MODIFIED_STREAM = 8; - const NOTIFY_REMOVED_BY_DELETE = 9; - /** * Get the name of the share * @@ -145,8 +134,7 @@ interface IShare { /** * @param string $path - * @param callable $callback callable which will be called for each received change - * @return mixed + * @return INotifyHandler */ - public function notify($path, callable $callback); + public function notify($path); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeFileInfo.php b/apps/files_external/3rdparty/icewind/smb/src/NativeFileInfo.php index 6ef5cf0c5b9..6cb070196a6 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/NativeFileInfo.php +++ b/apps/files_external/3rdparty/icewind/smb/src/NativeFileInfo.php @@ -26,7 +26,7 @@ class NativeFileInfo implements IFileInfo { protected $share; /** - * @var array | null + * @var array|null */ protected $statCache; @@ -66,7 +66,7 @@ class NativeFileInfo implements IFileInfo { * @return array */ protected function stat() { - if (!$this->statCache) { + if (is_null($this->statCache)) { $this->statCache = $this->share->getStat($this->getPath()); } return $this->statCache; diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php b/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php index 51e16d1841f..7efa34df370 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php @@ -60,6 +60,7 @@ class NativeShare extends AbstractShare { } private function buildUrl($path) { + $this->connect(); $this->verifyPath($path); $url = sprintf('smb://%s/%s', $this->server->getHost(), $this->name); if ($path) { @@ -80,7 +81,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\InvalidTypeException */ public function dir($path) { - $this->connect(); $files = array(); $dh = $this->state->opendir($this->buildUrl($path)); @@ -97,14 +97,13 @@ class NativeShare extends AbstractShare { /** * @param string $path - * @return \Icewind\SMB\IFileInfo[] + * @return \Icewind\SMB\IFileInfo */ public function stat($path) { return new NativeFileInfo($this, $path, basename($path), $this->getStat($path)); } public function getStat($path) { - $this->connect(); return $this->state->stat($this->buildUrl($path)); } @@ -118,7 +117,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\AlreadyExistsException */ public function mkdir($path) { - $this->connect(); return $this->state->mkdir($this->buildUrl($path)); } @@ -132,7 +130,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\InvalidTypeException */ public function rmdir($path) { - $this->connect(); return $this->state->rmdir($this->buildUrl($path)); } @@ -146,7 +143,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\InvalidTypeException */ public function del($path) { - $this->connect(); return $this->state->unlink($this->buildUrl($path)); } @@ -161,7 +157,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\AlreadyExistsException */ public function rename($from, $to) { - $this->connect(); return $this->state->rename($this->buildUrl($from), $this->buildUrl($to)); } @@ -176,7 +171,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\InvalidTypeException */ public function put($source, $target) { - $this->connect(); $sourceHandle = fopen($source, 'rb'); $targetHandle = $this->state->create($this->buildUrl($target)); @@ -214,7 +208,6 @@ class NativeShare extends AbstractShare { throw new InvalidResourceException('Failed opening local file "' . $target . '" for writing: ' . $reason); } - $this->connect(); $sourceHandle = $this->state->open($this->buildUrl($source), 'r'); if (!$sourceHandle) { fclose($targetHandle); @@ -238,7 +231,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\InvalidTypeException */ public function read($source) { - $this->connect(); $url = $this->buildUrl($source); $handle = $this->state->open($url, 'r'); return NativeStream::wrap($this->state, $handle, 'r', $url); @@ -254,7 +246,6 @@ class NativeShare extends AbstractShare { * @throws \Icewind\SMB\Exception\InvalidTypeException */ public function write($source) { - $this->connect(); $url = $this->buildUrl($source); $handle = $this->state->create($url); return NativeStream::wrap($this->state, $handle, 'w', $url); @@ -268,10 +259,7 @@ class NativeShare extends AbstractShare { * @return string the attribute value */ public function getAttribute($path, $attribute) { - $this->connect(); - - $result = $this->state->getxattr($this->buildUrl($path), $attribute); - return $result; + return $this->state->getxattr($this->buildUrl($path), $attribute); } /** @@ -283,7 +271,6 @@ class NativeShare extends AbstractShare { * @return string the attribute value */ public function setAttribute($path, $attribute, $value) { - $this->connect(); if ($attribute === 'system.dos_attr.mode' and is_int($value)) { $value = '0x' . dechex($value); @@ -303,14 +290,13 @@ class NativeShare extends AbstractShare { /** * @param string $path - * @param callable $callback callable which will be called for each received change - * @return mixed + * @return INotifyHandler */ - public function notify($path, callable $callback) { + public function notify($path) { // php-smbclient does support notify (https://github.com/eduardok/libsmbclient-php/issues/29) // so we use the smbclient based backend for this $share = new Share($this->server, $this->getName()); - $share->notify($path, $callback); + return $share->notify($path); } public function __destruct() { diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeState.php b/apps/files_external/3rdparty/icewind/smb/src/NativeState.php index e3e344d9e01..7ddce831853 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/NativeState.php +++ b/apps/files_external/3rdparty/icewind/smb/src/NativeState.php @@ -7,16 +7,7 @@ namespace Icewind\SMB; -use Icewind\SMB\Exception\AlreadyExistsException; -use Icewind\SMB\Exception\ConnectionRefusedException; use Icewind\SMB\Exception\Exception; -use Icewind\SMB\Exception\ForbiddenException; -use Icewind\SMB\Exception\HostDownException; -use Icewind\SMB\Exception\InvalidTypeException; -use Icewind\SMB\Exception\NoRouteToHostException; -use Icewind\SMB\Exception\NotEmptyException; -use Icewind\SMB\Exception\NotFoundException; -use Icewind\SMB\Exception\TimedOutException; /** * Low level wrapper for libsmbclient-php for error handling @@ -31,44 +22,39 @@ class NativeState { protected $connected = false; + // todo replace with static once <5.6 support is dropped + // see error.h + private static $exceptionMap = [ + 1 => '\Icewind\SMB\Exception\ForbiddenException', + 2 => '\Icewind\SMB\Exception\NotFoundException', + 13 => '\Icewind\SMB\Exception\ForbiddenException', + 17 => '\Icewind\SMB\Exception\AlreadyExistsException', + 20 => '\Icewind\SMB\Exception\InvalidTypeException', + 21 => '\Icewind\SMB\Exception\InvalidTypeException', + 39 => '\Icewind\SMB\Exception\NotEmptyException', + 110 => '\Icewind\SMB\Exception\TimedOutException', + 111 => '\Icewind\SMB\Exception\ConnectionRefusedException', + 112 => '\Icewind\SMB\Exception\HostDownException', + 113 => '\Icewind\SMB\Exception\NoRouteToHostException' + ]; + protected function handleError($path) { $error = smbclient_state_errno($this->state); - switch ($error) { - // see error.h - case 0; - return; - case 1: - case 13: - throw new ForbiddenException($path, $error); - case 2: - throw new NotFoundException($path, $error); - case 17: - throw new AlreadyExistsException($path, $error); - case 20: - throw new InvalidTypeException($path, $error); - case 21: - throw new InvalidTypeException($path, $error); - case 39: - throw new NotEmptyException($path, $error); - case 110: - throw new TimedOutException($path, $error); - case 111: - throw new ConnectionRefusedException($path, $error); - case 112: - throw new HostDownException($path, $error); - case 113: - throw new NoRouteToHostException($path, $error); - default: - $message = 'Unknown error (' . $error . ')'; - if ($path) { - $message .= ' for ' . $path; - } - throw new Exception($message, $error); + if ($error === 0) { + return; } + throw Exception::fromMap(self::$exceptionMap, $error, $path); } - protected function testResult($result, $path) { + protected function testResult($result, $uri) { if ($result === false or $result === null) { + // smb://host/share/path + if (is_string($uri)) { + list(, , , , $path) = explode('/', $uri, 5); + $path = '/' . $path; + } else { + $path = null; + } $this->handleError($path); } } @@ -246,7 +232,7 @@ 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. + * @return int|bool new file offset as measured from the start of the file on success, false on failure. */ public function lseek($file, $offset, $whence = SEEK_SET) { $result = @smbclient_lseek($this->state, $file, $offset, $whence); diff --git a/apps/files_external/3rdparty/icewind/smb/src/Parser.php b/apps/files_external/3rdparty/icewind/smb/src/Parser.php index fc1d7f283a8..5cc5acbdf56 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Parser.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Parser.php @@ -9,19 +9,38 @@ namespace Icewind\SMB; use Icewind\SMB\Exception\AccessDeniedException; use Icewind\SMB\Exception\AlreadyExistsException; +use Icewind\SMB\Exception\AuthenticationException; use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\FileInUseException; +use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\Exception\InvalidResourceException; use Icewind\SMB\Exception\InvalidTypeException; +use Icewind\SMB\Exception\NoLoginServerException; use Icewind\SMB\Exception\NotEmptyException; use Icewind\SMB\Exception\NotFoundException; class Parser { + const MSG_NOT_FOUND = 'Error opening local file '; + /** * @var \Icewind\SMB\TimeZoneProvider */ protected $timeZoneProvider; + // todo replace with static once <5.6 support is dropped + // see error.h + private static $exceptionMap = [ + ErrorCodes::PathNotFound => '\Icewind\SMB\Exception\NotFoundException', + ErrorCodes::ObjectNotFound => '\Icewind\SMB\Exception\NotFoundException', + ErrorCodes::NoSuchFile => '\Icewind\SMB\Exception\NotFoundException', + ErrorCodes::NameCollision => '\Icewind\SMB\Exception\AlreadyExistsException', + ErrorCodes::AccessDenied => '\Icewind\SMB\Exception\AccessDeniedException', + ErrorCodes::DirectoryNotEmpty => '\Icewind\SMB\Exception\NotEmptyException', + ErrorCodes::FileIsADirectory => '\Icewind\SMB\Exception\InvalidTypeException', + ErrorCodes::NotADirectory => '\Icewind\SMB\Exception\InvalidTypeException', + ErrorCodes::SharingViolation => '\Icewind\SMB\Exception\FileInUseException' + ]; + /** * @param \Icewind\SMB\TimeZoneProvider $timeZoneProvider */ @@ -29,50 +48,54 @@ class Parser { $this->timeZoneProvider = $timeZoneProvider; } - public function checkForError($output, $path) { - if (count($output) === 0) { - return true; - } else { - if (strpos($output[0], 'does not exist')) { - throw new NotFoundException($path); - } - $parts = explode(' ', $output[0]); - $error = false; - foreach ($parts as $part) { - if (substr($part, 0, 9) === 'NT_STATUS') { - $error = $part; - } + private function getErrorCode($line) { + $parts = explode(' ', $line); + foreach ($parts as $part) { + if (substr($part, 0, 9) === 'NT_STATUS') { + return $part; } + } + return false; + } - $notFoundMsg = 'Error opening local file '; - if (substr($output[0], 0, strlen($notFoundMsg)) === $notFoundMsg) { - $localPath = substr($output[0], strlen($notFoundMsg)); - throw new InvalidResourceException('Failed opening local file "' . $localPath . '" for writing'); - } + public function checkForError($output, $path) { + if (strpos($output[0], 'does not exist')) { + throw new NotFoundException($path); + } + $error = $this->getErrorCode($output[0]); - switch ($error) { - case ErrorCodes::PathNotFound: - case ErrorCodes::ObjectNotFound: - case ErrorCodes::NoSuchFile: - throw new NotFoundException($path); - case ErrorCodes::NameCollision: - throw new AlreadyExistsException($path); - case ErrorCodes::AccessDenied: - throw new AccessDeniedException($path); - case ErrorCodes::DirectoryNotEmpty: - throw new NotEmptyException($path); - case ErrorCodes::FileIsADirectory: - case ErrorCodes::NotADirectory: - throw new InvalidTypeException($path); - case ErrorCodes::SharingViolation: - throw new FileInUseException($path); - default: - $message = 'Unknown error (' . $error . ')'; - if ($path) { - $message .= ' for ' . $path; - } - throw new Exception($message); - } + if (substr($output[0], 0, strlen(self::MSG_NOT_FOUND)) === self::MSG_NOT_FOUND) { + $localPath = substr($output[0], strlen(self::MSG_NOT_FOUND)); + throw new InvalidResourceException('Failed opening local file "' . $localPath . '" for writing'); + } + + throw Exception::fromMap(self::$exceptionMap, $error, $path); + } + + /** + * check if the first line holds a connection failure + * + * @param $line + * @throws AuthenticationException + * @throws InvalidHostException + * @throws NoLoginServerException + */ + public function checkConnectionError($line) { + $line = rtrim($line, ')'); + if (substr($line, -23) === ErrorCodes::LogonFailure) { + throw new AuthenticationException('Invalid login'); + } + if (substr($line, -26) === ErrorCodes::BadHostName) { + throw new InvalidHostException('Invalid hostname'); + } + if (substr($line, -22) === ErrorCodes::Unsuccessful) { + throw new InvalidHostException('Connection unsuccessful'); + } + if (substr($line, -28) === ErrorCodes::ConnectionRefused) { + throw new InvalidHostException('Connection refused'); + } + if (substr($line, -26) === ErrorCodes::NoLogonServers) { + throw new NoLoginServerException('No login server'); } } @@ -95,9 +118,7 @@ class Parser { } public function parseStat($output) { - $mtime = 0; - $mode = 0; - $size = 0; + $data = []; foreach ($output as $line) { // A line = explode statement may not fill all array elements // properly. May happen when accessing non Windows Fileservers @@ -105,20 +126,13 @@ class Parser { $name = isset($words[0]) ? $words[0] : ''; $value = isset($words[1]) ? $words[1] : ''; $value = trim($value); - if ($name === 'write_time') { - $mtime = strtotime($value); - } else if ($name === 'attributes') { - $mode = hexdec(substr($value, 1, -1)); - } else if ($name === 'stream') { - list(, $size,) = explode(' ', $value); - $size = intval($size); - } + $data[$name] = $value; } - return array( - 'mtime' => $mtime, - 'mode' => $mode, - 'size' => $size - ); + return [ + 'mtime' => strtotime($data['write_time']), + 'mode' => hexdec(substr($data['attributes'], strpos($data['attributes'], '('), -1)), + 'size' => isset($data['stream']) ? intval(explode(' ', $data['stream'])[1]) : 0 + ]; } public function parseDir($output, $basePath) { @@ -139,4 +153,17 @@ class Parser { } return $content; } + + public function parseListShares($output) { + $shareNames = array(); + foreach ($output as $line) { + if (strpos($line, '|')) { + list($type, $name, $description) = explode('|', $line); + if (strtolower($type) === 'disk') { + $shareNames[$name] = $description; + } + } + } + return $shareNames; + } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php b/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php index 88ab046ef38..e9349716430 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php +++ b/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php @@ -88,7 +88,7 @@ class RawConnection { /** * read a line of output * - * @return string + * @return string|false */ public function readLine() { return stream_get_line($this->getOutputStream(), 4086, "\n"); diff --git a/apps/files_external/3rdparty/icewind/smb/src/Server.php b/apps/files_external/3rdparty/icewind/smb/src/Server.php index 25f17201397..12692eb4c6e 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Server.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Server.php @@ -135,32 +135,11 @@ class Server { $connection = new RawConnection($command); $connection->writeAuthentication($this->getUser(), $this->getPassword()); $output = $connection->readAll(); + $parser = new Parser($this->timezoneProvider); - $line = $output[0]; + $parser->checkConnectionError($output[0]); - $line = rtrim($line, ')'); - if (substr($line, -23) === ErrorCodes::LogonFailure) { - throw new AuthenticationException(); - } - if (substr($line, -26) === ErrorCodes::BadHostName) { - throw new InvalidHostException(); - } - if (substr($line, -22) === ErrorCodes::Unsuccessful) { - throw new InvalidHostException(); - } - if (substr($line, -28) === ErrorCodes::ConnectionRefused) { - throw new InvalidHostException(); - } - - $shareNames = array(); - foreach ($output as $line) { - if (strpos($line, '|')) { - list($type, $name, $description) = explode('|', $line); - if (strtolower($type) === 'disk') { - $shareNames[$name] = $description; - } - } - } + $shareNames = $parser->parseListShares($output); $shares = array(); foreach ($shareNames as $name => $description) { @@ -174,7 +153,7 @@ class Server { * @return \Icewind\SMB\IShare */ public function getShare($name) { - return new Share($this, $name); + return new Share($this, $name, $this->system); } /** diff --git a/apps/files_external/3rdparty/icewind/smb/src/Share.php b/apps/files_external/3rdparty/icewind/smb/src/Share.php index 21f8fe5b139..ba8bbbbb8ca 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Share.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Share.php @@ -8,6 +8,7 @@ namespace Icewind\SMB; use Icewind\SMB\Exception\ConnectionException; +use Icewind\SMB\Exception\DependencyException; use Icewind\SMB\Exception\FileInUseException; use Icewind\SMB\Exception\InvalidTypeException; use Icewind\SMB\Exception\NotFoundException; @@ -42,24 +43,30 @@ class Share extends AbstractShare { /** * @param Server $server * @param string $name + * @param System $system */ - public function __construct($server, $name) { + public function __construct($server, $name, System $system = null) { parent::__construct(); $this->server = $server; $this->name = $name; - $this->system = new System(); + $this->system = (!is_null($system)) ? $system : new System(); $this->parser = new Parser(new TimeZoneProvider($this->server->getHost(), $this->system)); } protected function getConnection() { $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; - $command = sprintf('stdbuf -o0 %s %s --authentication-file=%s %s', + $smbClientPath = $this->system->getSmbclientPath(); + if (!$smbClientPath) { + throw new DependencyException('Can\'t find smbclient binary in path'); + } + $command = sprintf('%s%s %s --authentication-file=%s %s', + $this->system->hasStdBuf() ? 'stdbuf -o0 ' : '', $this->system->getSmbclientPath(), $workgroupArgument, System::getFD(3), escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) ); - $connection = new Connection($command); + $connection = new Connection($command, $this->parser); $connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); if (!$connection->isValid()) { throw new ConnectionException(); @@ -97,8 +104,8 @@ class Share extends AbstractShare { } protected function simpleCommand($command, $path) { - $path = $this->escapePath($path); - $cmd = $command . ' ' . $path; + $escapedPath = $this->escapePath($path); + $cmd = $command . ' ' . $escapedPath; $output = $this->execute($cmd); return $this->parseOutput($output, $path); } @@ -125,7 +132,7 @@ class Share extends AbstractShare { /** * @param string $path - * @return \Icewind\SMB\IFileInfo[] + * @return \Icewind\SMB\IFileInfo */ public function stat($path) { $escapedPath = $this->escapePath($path); @@ -216,8 +223,7 @@ class Share extends AbstractShare { public function rename($from, $to) { $path1 = $this->escapePath($from); $path2 = $this->escapePath($to); - $cmd = 'rename ' . $path1 . ' ' . $path2; - $output = $this->execute($cmd); + $output = $this->execute('rename ' . $path1 . ' ' . $path2); return $this->parseOutput($output, $to); } @@ -268,15 +274,8 @@ class Share extends AbstractShare { $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 - $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; - $command = sprintf('%s %s --authentication-file=%s %s', - $this->system->getSmbclientPath(), - $workgroupArgument, - System::getFD(3), - escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) - ); - $connection = new Connection($command); - $connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); + $connection = $this->getConnection(); + $connection->write('get ' . $source . ' ' . System::getFD(5)); $connection->write('exit'); $fh = $connection->getFileOutputStream(); @@ -297,17 +296,9 @@ class Share extends AbstractShare { $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 - $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; - $command = sprintf('%s %s --authentication-file=%s %s', - $this->system->getSmbclientPath(), - $workgroupArgument, - System::getFD(3), - escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) - ); - $connection = new Connection($command); - $connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); - $fh = $connection->getFileInputStream(); + $connection = $this->getConnection(); + $fh = $connection->getFileInputStream(); $connection->write('put ' . System::getFD(4) . ' ' . $target); $connection->write('exit'); @@ -343,30 +334,30 @@ class Share extends AbstractShare { $output = $this->execute($cmd); $this->parseOutput($output, $path); - // then set the modes we want - $cmd = 'setmode ' . $path . ' ' . $modeString; - $output = $this->execute($cmd); - return $this->parseOutput($output, $path); + if ($mode !== FileInfo::MODE_NORMAL) { + // then set the modes we want + $cmd = 'setmode ' . $path . ' ' . $modeString; + $output = $this->execute($cmd); + return $this->parseOutput($output, $path); + } else { + return true; + } } /** * @param string $path - * @param callable $callback callable which will be called for each received change - * @return mixed + * @return INotifyHandler + * @throws ConnectionException + * @throws DependencyException */ - public function notify($path, callable $callback) { + public function notify($path) { + if (!$this->system->hasStdBuf()) { //stdbuf is required to disable smbclient's output buffering + throw new DependencyException('stdbuf is required for usage of the notify command'); + } $connection = $this->getConnection(); // use a fresh connection since the notify command blocks the process $command = 'notify ' . $this->escapePath($path); $connection->write($command . PHP_EOL); - $connection->read(function ($line) use ($callback, $path) { - $code = (int)substr($line, 0, 4); - $subPath = substr($line, 5); - if ($path === '') { - return $callback($code, $subPath); - } else { - return $callback($code, $path . '/' . $subPath); - } - }); + return new NotifyHandler($connection, $path); } /** @@ -395,7 +386,12 @@ class Share extends AbstractShare { * @return bool */ protected function parseOutput($lines, $path = '') { - return $this->parser->checkForError($lines, $path); + if (count($lines) === 0) { + return true; + } else { + $this->parser->checkForError($lines, $path); + return false; + } } /** diff --git a/apps/files_external/3rdparty/icewind/smb/src/System.php b/apps/files_external/3rdparty/icewind/smb/src/System.php index 192a0b3877d..7c519988aa5 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/System.php +++ b/apps/files_external/3rdparty/icewind/smb/src/System.php @@ -14,6 +14,8 @@ class System { private $net; + private $stdbuf; + public static function getFD($num) { $folders = array( '/proc/self/fd', @@ -40,4 +42,14 @@ class System { } return $this->net; } + + public function hasStdBuf() { + if (!$this->stdbuf) { + $result = null; + $output = array(); + exec('which stdbuf 2>&1', $output, $result); + $this->stdbuf = $result === 0; + } + return $this->stdbuf; + } } diff --git a/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php b/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php index 86d7859a6f7..fcdf7e3e879 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php +++ b/apps/files_external/3rdparty/icewind/smb/src/TimeZoneProvider.php @@ -27,7 +27,7 @@ class TimeZoneProvider { * @param string $host * @param System $system */ - function __construct($host, System $system) { + public function __construct($host, System $system) { $this->host = $host; $this->system = $system; } |