Improve locating file descriptors and smbclient/net commands

This commit is contained in:
Robin Appelman 2015-12-31 20:38:39 +01:00
commit b865f430d6
5 changed files with 100 additions and 18 deletions

View file

@ -13,7 +13,8 @@
"icewind/streams": "0.2.*" "icewind/streams": "0.2.*"
}, },
"require-dev": { "require-dev": {
"satooshi/php-coveralls" : "dev-master" "satooshi/php-coveralls" : "dev-master",
"phpunit/phpunit": "^4.8"
}, },
"autoload" : { "autoload" : {
"psr-4": { "psr-4": {

View file

@ -11,7 +11,6 @@ use Icewind\SMB\Exception\AuthenticationException;
use Icewind\SMB\Exception\InvalidHostException; use Icewind\SMB\Exception\InvalidHostException;
class Server { class Server {
const CLIENT = 'smbclient';
const LOCALE = 'en_US.UTF-8'; const LOCALE = 'en_US.UTF-8';
/** /**
@ -34,6 +33,16 @@ class Server {
*/ */
protected $workgroup; protected $workgroup;
/**
* @var \Icewind\SMB\System
*/
private $system;
/**
* @var TimeZoneProvider
*/
private $timezoneProvider;
/** /**
* Check if the smbclient php extension is available * Check if the smbclient php extension is available
* *
@ -54,6 +63,8 @@ class Server {
$this->user = $user; $this->user = $user;
$this->workgroup = $workgroup; $this->workgroup = $workgroup;
$this->password = $password; $this->password = $password;
$this->system = new System();
$this->timezoneProvider = new TimeZoneProvider($host, $this->system);
} }
/** /**
@ -115,8 +126,12 @@ class Server {
*/ */
public function listShares() { public function listShares() {
$workgroupArgument = ($this->workgroup) ? ' -W ' . escapeshellarg($this->workgroup) : ''; $workgroupArgument = ($this->workgroup) ? ' -W ' . escapeshellarg($this->workgroup) : '';
$command = Server::CLIENT . $workgroupArgument . ' --authentication-file=/proc/self/fd/3' . $command = sprintf('%s %s --authentication-file=%s -gL %s',
' -gL ' . escapeshellarg($this->getHost()); $this->system->getSmbclientPath(),
$workgroupArgument,
System::getFD(3),
escapeshellarg($this->getHost())
);
$connection = new RawConnection($command); $connection = new RawConnection($command);
$connection->writeAuthentication($this->getUser(), $this->getPassword()); $connection->writeAuthentication($this->getUser(), $this->getPassword());
$output = $connection->readAll(); $output = $connection->readAll();
@ -166,7 +181,6 @@ class Server {
* @return string * @return string
*/ */
public function getTimeZone() { public function getTimeZone() {
$command = 'net time zone -S ' . escapeshellarg($this->getHost()); return $this->timezoneProvider->get();
return exec($command);
} }
} }

View file

@ -34,6 +34,11 @@ class Share extends AbstractShare {
*/ */
protected $parser; protected $parser;
/**
* @var \Icewind\SMB\System
*/
private $system;
/** /**
* @param Server $server * @param Server $server
* @param string $name * @param string $name
@ -42,7 +47,8 @@ class Share extends AbstractShare {
parent::__construct(); parent::__construct();
$this->server = $server; $this->server = $server;
$this->name = $name; $this->name = $name;
$this->parser = new Parser(new TimeZoneProvider($this->server->getHost())); $this->system = new System();
$this->parser = new Parser(new TimeZoneProvider($this->server->getHost(), $this->system));
} }
/** /**
@ -55,9 +61,10 @@ class Share extends AbstractShare {
return; return;
} }
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s', $command = sprintf('%s %s --authentication-file=%s %s',
Server::CLIENT, $this->system->getSmbclientPath(),
$workgroupArgument, $workgroupArgument,
System::getFD(3),
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
); );
$this->connection = new Connection($command); $this->connection = new Connection($command);
@ -257,14 +264,15 @@ class Share extends AbstractShare {
// since returned stream is closed by the caller we need to create a new instance // 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 // since we can't re-use the same file descriptor over multiple calls
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s', $command = sprintf('%s %s --authentication-file=%s %s',
Server::CLIENT, $this->system->getSmbclientPath(),
$workgroupArgument, $workgroupArgument,
System::getFD(3),
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
); );
$connection = new Connection($command); $connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); $connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
$connection->write('get ' . $source . ' /proc/self/fd/5'); $connection->write('get ' . $source . ' ' . System::getFD(5));
$connection->write('exit'); $connection->write('exit');
$fh = $connection->getFileOutputStream(); $fh = $connection->getFileOutputStream();
stream_context_set_option($fh, 'file', 'connection', $connection); stream_context_set_option($fh, 'file', 'connection', $connection);
@ -285,16 +293,17 @@ class Share extends AbstractShare {
// since returned stream is closed by the caller we need to create a new instance // 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 // since we can't re-use the same file descriptor over multiple calls
$workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
$command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s', $command = sprintf('%s %s --authentication-file=%s %s',
Server::CLIENT, $this->system->getSmbclientPath(),
$workgroupArgument, $workgroupArgument,
System::getFD(3),
escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
); );
$connection = new Connection($command); $connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); $connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
$fh = $connection->getFileInputStream(); $fh = $connection->getFileInputStream();
$connection->write('put /proc/self/fd/4 ' . $target); $connection->write('put ' . System::getFD(4) . ' ' . $target);
$connection->write('exit'); $connection->write('exit');
// use a close callback to ensure the upload is finished before continuing // use a close callback to ensure the upload is finished before continuing

43
src/System.php Normal file
View file

@ -0,0 +1,43 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Licensed under the MIT license:
* http://opensource.org/licenses/MIT
*/
namespace Icewind\SMB;
use Icewind\SMB\Exception\Exception;
class System {
private $smbclient;
private $net;
public static function getFD($num) {
$folders = [
'/proc/self/fd',
'/dev/fd'
];
foreach ($folders as $folder) {
if (file_exists($folder)) {
return $folder . '/' . $num;
}
}
throw new Exception('Cant find file descriptor path');
}
public function getSmbclientPath() {
if (!$this->smbclient) {
$this->smbclient = trim(`which smbclient`);
}
return $this->smbclient;
}
public function getNetPath() {
if (!$this->net) {
$this->net = trim(`which net`);
}
return $this->net;
}
}

View file

@ -19,16 +19,31 @@ class TimeZoneProvider {
private $timeZone; private $timeZone;
/** /**
* @param string $host * @var System
*/ */
function __construct($host) { private $system;
/**
* @param string $host
* @param System $system
*/
function __construct($host, System $system) {
$this->host = $host; $this->host = $host;
$this->system = $system;
} }
public function get() { public function get() {
if (!$this->timeZone) { if (!$this->timeZone) {
$command = 'net time zone -S ' . escapeshellarg($this->host); $net = $this->system->getNetPath();
if ($net) {
$command = sprintf('%s time zone -S %s',
$net,
escapeshellarg($this->host)
);
$this->timeZone = exec($command); $this->timeZone = exec($command);
} else { // fallback to server timezone
$this->timeZone = date_default_timezone_get();
}
} }
return $this->timeZone; return $this->timeZone;
} }