-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
new SMB storage backend #4770
new SMB storage backend #4770
Changes from 9 commits
bc276ae
a85d38d
aad2304
a77119f
37f4c55
88e5712
a73d058
8a8110b
1db7e7b
1770fdc
5141028
5c4eb85
5812a5b
8631534
bd781d7
8079a9c
a2764ab
be3a5c6
d7f160c
6beee91
d515aa2
d7fdbc8
538961f
a674726
80f4e68
48e8e8a
8cd05d7
5baec0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2012 Robin Appelman <[email protected]> | ||
* This file is licensed under the Affero General Public License version 3 or | ||
* later. | ||
* See the COPYING-README file. | ||
*/ | ||
|
||
set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__); | ||
|
||
require_once 'errors.php'; | ||
|
||
spl_autoload_register(function ($class) { | ||
if (substr($class, 0, 4) == 'SMB\\') { | ||
$class = strtolower($class); | ||
$file = str_replace('\\', '/', substr($class, 4)); | ||
include __DIR__ . '/' . $file . '.php'; | ||
} | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2013 Robin Appelman <[email protected]> | ||
* This file is licensed under the Affero General Public License version 3 or | ||
* later. | ||
* See the COPYING-README file. | ||
*/ | ||
|
||
namespace SMB; | ||
|
||
/** | ||
* Class CachingShare | ||
* | ||
* caches metadata from share | ||
* | ||
* @package SMB | ||
*/ | ||
class CachingShare extends Share { | ||
private $dirCache = array(); | ||
|
||
private function clear($path = null) { | ||
if (is_null($path)) { | ||
$this->dirCache = array(); | ||
} else { | ||
unset($this->dirCache[$path]); | ||
} | ||
} | ||
|
||
public function dir($path) { | ||
if (!isset($this->dirCache[$path])) { | ||
$this->dirCache[$path] = parent::dir($path); | ||
} | ||
return $this->dirCache[$path]; | ||
} | ||
|
||
public function mkdir($path) { | ||
$this->clear(dirname($path)); | ||
return parent::mkdir($path); | ||
} | ||
|
||
public function rmdir($path) { | ||
$this->clear(dirname($path)); | ||
return parent::rmdir($path); | ||
} | ||
|
||
public function del($path) { | ||
$this->clear(dirname($path)); | ||
return parent::del($path); | ||
} | ||
|
||
public function put($source, $target) { | ||
$this->clear(dirname($target)); | ||
return parent::put($source, $target); | ||
} | ||
|
||
public function rename($from, $to) { | ||
$this->clear(dirname($from)); | ||
$this->clear(dirname($to)); | ||
return parent::rename($from, $to); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2013 Robin Appelman <[email protected]> | ||
* This file is licensed under the Affero General Public License version 3 or | ||
* later. | ||
* See the COPYING-README file. | ||
*/ | ||
|
||
namespace SMB; | ||
|
||
class Connection extends RawConnection { | ||
const DELIMITER = 'smb:'; | ||
|
||
/** | ||
* send input to smbclient | ||
* | ||
* @param string $input | ||
*/ | ||
public function write($input) { | ||
parent::write($input . PHP_EOL); | ||
} | ||
|
||
/** | ||
* get all unprocessed output from smbclient untill the next prompt | ||
* | ||
* @throws ConnectionError | ||
* @return array | ||
*/ | ||
public function read() { | ||
if (!$this->isValid()) { | ||
throw new ConnectionError(); | ||
} | ||
$line = parent::read(); //first line is prompt | ||
$this->checkConnectionError($line); | ||
|
||
$output = array(); | ||
$line = parent::read(); | ||
$length = strlen(self::DELIMITER); | ||
while (substr($line, 0, $length) !== self::DELIMITER) { //next prompt functions as delimiter | ||
$output[] .= $line; | ||
$line = parent::read(); | ||
} | ||
return $output; | ||
} | ||
|
||
/** | ||
* check if the first line holds a connection failure | ||
* | ||
* @param $line | ||
* @throws AuthenticationException | ||
* @throws InvalidHostException | ||
*/ | ||
private function checkConnectionError($line) { | ||
$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(); | ||
} | ||
} | ||
|
||
public function close() { | ||
$this->write('close' . PHP_EOL); | ||
} | ||
|
||
public function __destruct() { | ||
$this->close(); | ||
parent::__destruct(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2012 Robin Appelman <[email protected]> | ||
* This file is licensed under the Affero General Public License version 3 or | ||
* later. | ||
* See the COPYING-README file. | ||
*/ | ||
|
||
namespace SMB; | ||
|
||
class NotFoundException extends \Exception { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these exceptions all required? Maybe some of the SPL exceptions could be reused. http://www.php.net/manual/en/spl.exceptions.php |
||
} | ||
|
||
class AlreadyExistsException extends \Exception { | ||
} | ||
|
||
class NotEmptyException extends \Exception { | ||
} | ||
|
||
class ConnectionError extends \Exception { | ||
} | ||
|
||
class AuthenticationException extends \Exception { | ||
} | ||
|
||
class InvalidHostException extends \Exception { | ||
} | ||
|
||
class AccessDeniedException extends \Exception { | ||
} | ||
|
||
class InvalidTypeException extends \Exception { | ||
} | ||
|
||
class ErrorCodes { | ||
/** | ||
* connection errors | ||
*/ | ||
const LogonFailure = 'NT_STATUS_LOGON_FAILURE'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I see how these constants are useful. Why not use the string constants verbatim? |
||
const BadHostName = 'NT_STATUS_BAD_NETWORK_NAME'; | ||
const Unsuccessful = 'NT_STATUS_UNSUCCESSFUL'; | ||
const ConnectionRefused = 'NT_STATUS_CONNECTION_REFUSED'; | ||
|
||
const PathNotFound = 'NT_STATUS_OBJECT_PATH_NOT_FOUND'; | ||
const NoSuchFile = 'NT_STATUS_NO_SUCH_FILE'; | ||
const ObjectNotFound = 'NT_STATUS_OBJECT_NAME_NOT_FOUND'; | ||
const NameCollision = 'NT_STATUS_OBJECT_NAME_COLLISION'; | ||
const AccessDenied = 'NT_STATUS_ACCESS_DENIED'; | ||
const DirectoryNotEmpty = 'NT_STATUS_DIRECTORY_NOT_EMPTY'; | ||
const FileIsADirectory = 'NT_STATUS_FILE_IS_A_DIRECTORY'; | ||
const NotADirectory = 'NT_STATUS_NOT_A_DIRECTORY'; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2013 Robin Appelman <[email protected]> | ||
* This file is licensed under the Affero General Public License version 3 or | ||
* later. | ||
* See the COPYING-README file. | ||
*/ | ||
|
||
namespace SMB; | ||
|
||
class RawConnection { | ||
/** | ||
* @var resource[] $pipes | ||
* | ||
* $pipes[0] holds STDIN for smbclient | ||
* $pipes[1] holds STDOUT for smbclient | ||
*/ | ||
private $pipes; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't these be available to subclasses? Personally, I think that the number of proper use-cases of private is just as limited as the number of use-cases for static. |
||
|
||
/** | ||
* @var resource $process | ||
*/ | ||
private $process; | ||
|
||
|
||
public function __construct($command) { | ||
$descriptorSpec = array( | ||
0 => array("pipe", "r"), | ||
1 => array("pipe", "w"), | ||
2 => array('file', '/dev/null', 'w') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to indicate this is a client for unix only, which is okay. I also remember discussing that on Windows native mounts and local storage should be used, which is okay, but it should be documented in the class description (or even checked). |
||
); | ||
setlocale(LC_ALL, Server::LOCALE); | ||
$this->process = proc_open($command, $descriptorSpec, $this->pipes, null, array( | ||
'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!! | ||
'LC_ALL' => Server::LOCALE | ||
)); | ||
if (!$this->isValid()) { | ||
throw new ConnectionError(); | ||
} | ||
} | ||
|
||
/** | ||
* check if the connection is still active | ||
* | ||
* @return bool | ||
*/ | ||
public function isValid() { | ||
if (is_resource($this->process)) { | ||
$status = proc_get_status($this->process); | ||
return $status['running']; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* send input to the process | ||
* | ||
* @param string $input | ||
*/ | ||
public function write($input) { | ||
fwrite($this->pipes[0], $input); | ||
fflush($this->pipes[0]); | ||
} | ||
|
||
/** | ||
* read a line of output | ||
* | ||
* @return array | ||
*/ | ||
public function read() { | ||
return trim(fgets($this->pipes[1])); | ||
} | ||
|
||
/** | ||
* get all output until the process closes | ||
* | ||
* @return array | ||
*/ | ||
public function readAll() { | ||
$output = array(); | ||
while ($line = $this->read()) { | ||
$output[] = $line; | ||
} | ||
return $output; | ||
} | ||
|
||
public function __destruct() { | ||
proc_terminate($this->process); | ||
proc_close($this->process); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this be done in a more automatic-autoload-approach, i.e. without registering your own autoloader?