Merge pull request #20207 from nextcloud/smb-3.2.1
update icewind/smb to 3.2.1
This commit is contained in:
commit
20ecbd60fd
|
@ -9,6 +9,6 @@
|
|||
},
|
||||
"require": {
|
||||
"icewind/streams": "0.7.1",
|
||||
"icewind/smb": "3.1.1"
|
||||
"icewind/smb": "3.2.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,29 +4,29 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "5639a09feff2318b1b69e11a10a81e7d",
|
||||
"content-hash": "adc3b3531ee8503b485092e60c569b42",
|
||||
"packages": [
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v3.1.1",
|
||||
"version": "v3.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "26b7b8780342d0e61313b464b880d50a2ea898e2"
|
||||
"reference": "5330edcc579a2dcc4759b8e5779eb5aa3385a878"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/26b7b8780342d0e61313b464b880d50a2ea898e2",
|
||||
"reference": "26b7b8780342d0e61313b464b880d50a2ea898e2",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/5330edcc579a2dcc4759b8e5779eb5aa3385a878",
|
||||
"reference": "5330edcc579a2dcc4759b8e5779eb5aa3385a878",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"icewind/streams": ">=0.2.0",
|
||||
"php": ">=5.6"
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.13",
|
||||
"phpunit/phpunit": "^5.7"
|
||||
"phpunit/phpunit": "^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
],
|
||||
"description": "php wrapper for smbclient and libsmbclient-php",
|
||||
"time": "2019-03-04T15:02:42+00:00"
|
||||
"time": "2020-03-24T18:19:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "icewind/streams",
|
||||
|
@ -97,5 +97,6 @@
|
|||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "1.1.0"
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
|
|||
$baseDir = $vendorDir;
|
||||
|
||||
return array(
|
||||
'Icewind\\SMB\\ACL' => $vendorDir . '/icewind/smb/src/ACL.php',
|
||||
'Icewind\\SMB\\AbstractServer' => $vendorDir . '/icewind/smb/src/AbstractServer.php',
|
||||
'Icewind\\SMB\\AbstractShare' => $vendorDir . '/icewind/smb/src/AbstractShare.php',
|
||||
'Icewind\\SMB\\AnonymousAuth' => $vendorDir . '/icewind/smb/src/AnonymousAuth.php',
|
||||
|
|
|
@ -13,6 +13,9 @@ class ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\Autoload\ClassLoader
|
||||
*/
|
||||
public static function getLoader()
|
||||
{
|
||||
if (null !== self::$loader) {
|
||||
|
|
|
@ -36,6 +36,7 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3
|
|||
);
|
||||
|
||||
public static $classMap = array (
|
||||
'Icewind\\SMB\\ACL' => __DIR__ . '/..' . '/icewind/smb/src/ACL.php',
|
||||
'Icewind\\SMB\\AbstractServer' => __DIR__ . '/..' . '/icewind/smb/src/AbstractServer.php',
|
||||
'Icewind\\SMB\\AbstractShare' => __DIR__ . '/..' . '/icewind/smb/src/AbstractShare.php',
|
||||
'Icewind\\SMB\\AnonymousAuth' => __DIR__ . '/..' . '/icewind/smb/src/AnonymousAuth.php',
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
[
|
||||
{
|
||||
"name": "icewind/smb",
|
||||
"version": "v3.1.1",
|
||||
"version_normalized": "3.1.1.0",
|
||||
"version": "v3.2.1",
|
||||
"version_normalized": "3.2.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/icewind1991/SMB.git",
|
||||
"reference": "26b7b8780342d0e61313b464b880d50a2ea898e2"
|
||||
"reference": "5330edcc579a2dcc4759b8e5779eb5aa3385a878"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/26b7b8780342d0e61313b464b880d50a2ea898e2",
|
||||
"reference": "26b7b8780342d0e61313b464b880d50a2ea898e2",
|
||||
"url": "https://api.github.com/repos/icewind1991/SMB/zipball/5330edcc579a2dcc4759b8e5779eb5aa3385a878",
|
||||
"reference": "5330edcc579a2dcc4759b8e5779eb5aa3385a878",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"icewind/streams": ">=0.2.0",
|
||||
"php": ">=5.6"
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.13",
|
||||
"phpunit/phpunit": "^5.7"
|
||||
"phpunit/phpunit": "^7.0"
|
||||
},
|
||||
"time": "2019-03-04T15:02:42+00:00",
|
||||
"time": "2020-03-24T18:19:18+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
vendor
|
||||
composer.lock
|
||||
.php_cs.cache
|
||||
|
||||
listen.php
|
||||
test.php
|
||||
|
|
|
@ -26,7 +26,7 @@ use Icewind\SMB\BasicAuth;
|
|||
require('vendor/autoload.php');
|
||||
|
||||
$serverFactory = new ServerFactory();
|
||||
$auth = new BasicAuth('test', 'workgroup', 'test');
|
||||
$auth = new BasicAuth('user', 'workgroup', 'password');
|
||||
$server = $serverFactory->createServer('localhost', $auth);
|
||||
|
||||
$share = $server->getShare('test');
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
}
|
||||
],
|
||||
"require" : {
|
||||
"php": ">=5.6",
|
||||
"php": ">=7.1",
|
||||
"icewind/streams": ">=0.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.7",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"friendsofphp/php-cs-fixer": "^2.13"
|
||||
},
|
||||
"autoload" : {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2020 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 ACL {
|
||||
const TYPE_ALLOW = 0;
|
||||
const TYPE_DENY = 1;
|
||||
|
||||
const MASK_READ = 0x0001;
|
||||
const MASK_WRITE = 0x0002;
|
||||
const MASK_EXECUTE = 0x00020;
|
||||
const MASK_DELETE = 0x10000;
|
||||
|
||||
const FLAG_OBJECT_INHERIT = 0x1;
|
||||
const FLAG_CONTAINER_INHERIT = 0x2;
|
||||
|
||||
private $type;
|
||||
private $flags;
|
||||
private $mask;
|
||||
|
||||
public function __construct(int $type, int $flags, int $mask) {
|
||||
$this->type = $type;
|
||||
$this->flags = $flags;
|
||||
$this->mask = $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the acl allows a specific permissions
|
||||
*
|
||||
* Note that this does not take inherited acls into account
|
||||
*
|
||||
* @param int $mask one of the ACL::MASK_* constants
|
||||
* @return bool
|
||||
*/
|
||||
public function allows(int $mask): bool {
|
||||
return $this->type === self::TYPE_ALLOW && ($this->mask & $mask) === $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the acl allows a specific permissions
|
||||
*
|
||||
* Note that this does not take inherited acls into account
|
||||
*
|
||||
* @param int $mask one of the ACL::MASK_* constants
|
||||
* @return bool
|
||||
*/
|
||||
public function denies(int $mask): bool {
|
||||
return $this->type === self::TYPE_DENY && ($this->mask & $mask) === $mask;
|
||||
}
|
||||
|
||||
public function getType(): int {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getFlags(): int {
|
||||
return $this->flags;
|
||||
}
|
||||
|
||||
public function getMask(): int {
|
||||
return $this->mask;
|
||||
}
|
||||
}
|
|
@ -65,4 +65,9 @@ interface IFileInfo {
|
|||
* @return bool
|
||||
*/
|
||||
public function isArchived();
|
||||
|
||||
/**
|
||||
* @return ACL[]
|
||||
*/
|
||||
public function getAcls(): array;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,13 @@ interface ISystem {
|
|||
*/
|
||||
public function getNetPath();
|
||||
|
||||
/**
|
||||
* Get the full path to the `smbcacls` binary of false if the binary is not available
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function getSmbcAclsPath();
|
||||
|
||||
/**
|
||||
* Get the full path to the `stdbuf` binary of false if the binary is not available
|
||||
*
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
|
||||
namespace Icewind\SMB\Native;
|
||||
|
||||
use Icewind\SMB\ACL;
|
||||
use Icewind\SMB\IFileInfo;
|
||||
|
||||
class NativeFileInfo implements IFileInfo {
|
||||
const MODE_FILE = 0100000;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -30,10 +29,7 @@ class NativeFileInfo implements IFileInfo {
|
|||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
protected $statCache = null;
|
||||
|
||||
/** @var callable|null */
|
||||
protected $statCallback = null;
|
||||
protected $attributeCache = null;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
|
@ -44,20 +40,11 @@ class NativeFileInfo implements IFileInfo {
|
|||
* @param NativeShare $share
|
||||
* @param string $path
|
||||
* @param string $name
|
||||
* @param array|callable $stat
|
||||
*/
|
||||
public function __construct($share, $path, $name, $stat) {
|
||||
public function __construct($share, $path, $name) {
|
||||
$this->share = $share;
|
||||
$this->path = $path;
|
||||
$this->name = $name;
|
||||
|
||||
if (is_array($stat)) {
|
||||
$this->statCache = $stat;
|
||||
} elseif (is_callable($stat)) {
|
||||
$this->statCallback = $stat;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('$stat needs to be an array or callback');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,10 +65,20 @@ class NativeFileInfo implements IFileInfo {
|
|||
* @return array
|
||||
*/
|
||||
protected function stat() {
|
||||
if (is_null($this->statCache)) {
|
||||
$this->statCache = call_user_func($this->statCallback);
|
||||
if (is_null($this->attributeCache)) {
|
||||
$rawAttributes = explode(',', $this->share->getAttribute($this->path, 'system.dos_attr.*'));
|
||||
$this->attributeCache = [];
|
||||
foreach ($rawAttributes as $rawAttribute) {
|
||||
[$name, $value] = explode(':', $rawAttribute);
|
||||
$name = strtolower($name);
|
||||
if ($name == 'mode') {
|
||||
$this->attributeCache[$name] = (int)hexdec(substr($value, 2));
|
||||
} else {
|
||||
$this->attributeCache[$name] = (int)$value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->statCache;
|
||||
return $this->attributeCache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,27 +94,22 @@ class NativeFileInfo implements IFileInfo {
|
|||
*/
|
||||
public function getMTime() {
|
||||
$stat = $this->stat();
|
||||
return $stat['mtime'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDirectory() {
|
||||
$stat = $this->stat();
|
||||
return !($stat['mode'] & self::MODE_FILE);
|
||||
return $stat['change_time'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function getMode() {
|
||||
if (!$this->modeCache) {
|
||||
$attribute = $this->share->getAttribute($this->path, 'system.dos_attr.mode');
|
||||
// parse hex string
|
||||
$this->modeCache = (int)hexdec(substr($attribute, 2));
|
||||
}
|
||||
return $this->modeCache;
|
||||
return $this->stat()['mode'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDirectory() {
|
||||
$mode = $this->getMode();
|
||||
return (bool)($mode & IFileInfo::MODE_DIRECTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,4 +143,22 @@ class NativeFileInfo implements IFileInfo {
|
|||
$mode = $this->getMode();
|
||||
return (bool)($mode & IFileInfo::MODE_ARCHIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ACL[]
|
||||
*/
|
||||
public function getAcls(): array {
|
||||
$acls = [];
|
||||
$attribute = $this->share->getAttribute($this->path, 'system.nt_sec_desc.acl.*+');
|
||||
|
||||
foreach (explode(',', $attribute) as $acl) {
|
||||
[$user, $permissions] = explode(':', $acl, 2);
|
||||
[$type, $flags, $mask] = explode('/', $permissions);
|
||||
$mask = hexdec($mask);
|
||||
|
||||
$acls[$user] = new ACL($type, $flags, $mask);
|
||||
}
|
||||
|
||||
return $acls;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,9 +94,7 @@ class NativeShare extends AbstractShare {
|
|||
$name = $file['name'];
|
||||
if ($name !== '.' and $name !== '..') {
|
||||
$fullPath = $path . '/' . $name;
|
||||
$files [] = new NativeFileInfo($this, $fullPath, $name, function () use ($fullPath) {
|
||||
return $this->getStat($fullPath);
|
||||
});
|
||||
$files [] = new NativeFileInfo($this, $fullPath, $name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +107,12 @@ class NativeShare extends AbstractShare {
|
|||
* @return \Icewind\SMB\IFileInfo
|
||||
*/
|
||||
public function stat($path) {
|
||||
return new NativeFileInfo($this, $path, self::mb_basename($path), $this->getStat($path));
|
||||
$info = new NativeFileInfo($this, $path, self::mb_basename($path));
|
||||
|
||||
// trigger attribute loading
|
||||
$info->getSize();
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,10 +132,6 @@ class NativeShare extends AbstractShare {
|
|||
return '';
|
||||
}
|
||||
|
||||
private function getStat($path) {
|
||||
return $this->getState()->stat($this->buildUrl($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a folder on the share
|
||||
*
|
||||
|
@ -223,6 +222,12 @@ class NativeShare extends AbstractShare {
|
|||
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) {
|
||||
$error = error_get_last();
|
||||
|
@ -231,15 +236,10 @@ class NativeShare extends AbstractShare {
|
|||
} else {
|
||||
$reason = 'Unknown error';
|
||||
}
|
||||
$this->getState()->close($sourceHandle);
|
||||
throw new InvalidResourceException('Failed opening local file "' . $target . '" for writing: ' . $reason);
|
||||
}
|
||||
|
||||
$sourceHandle = $this->getState()->open($this->buildUrl($source), 'r');
|
||||
if (!$sourceHandle) {
|
||||
fclose($targetHandle);
|
||||
throw new InvalidResourceException('Failed opening remote file "' . $source . '" for reading');
|
||||
}
|
||||
|
||||
while ($data = $this->getState()->read($sourceHandle, NativeReadStream::CHUNK_SIZE)) {
|
||||
fwrite($targetHandle, $data);
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ class NativeShare extends AbstractShare {
|
|||
*/
|
||||
public function append($source) {
|
||||
$url = $this->buildUrl($source);
|
||||
$handle = $this->getState()->open($url, "a");
|
||||
$handle = $this->getState()->open($url, "a+");
|
||||
return NativeWriteStream::wrap($this->getState(), $handle, "a", $url);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace Icewind\SMB\Native;
|
|||
|
||||
use Icewind\SMB\Exception\AlreadyExistsException;
|
||||
use Icewind\SMB\Exception\ConnectionRefusedException;
|
||||
use Icewind\SMB\Exception\ConnectionResetException;
|
||||
use Icewind\SMB\Exception\Exception;
|
||||
use Icewind\SMB\Exception\FileInUseException;
|
||||
use Icewind\SMB\Exception\ForbiddenException;
|
||||
|
@ -48,6 +49,7 @@ class NativeState {
|
|||
22 => InvalidArgumentException::class,
|
||||
28 => OutOfSpaceException::class,
|
||||
39 => NotEmptyException::class,
|
||||
104 => ConnectionResetException::class,
|
||||
110 => TimedOutException::class,
|
||||
111 => ConnectionRefusedException::class,
|
||||
112 => HostDownException::class,
|
||||
|
|
|
@ -41,6 +41,10 @@ class System implements ISystem {
|
|||
return $this->getBinaryPath('net');
|
||||
}
|
||||
|
||||
public function getSmbcAclsPath() {
|
||||
return $this->getBinaryPath('smbcacls');
|
||||
}
|
||||
|
||||
public function getStdBufPath() {
|
||||
return $this->getBinaryPath('stdbuf');
|
||||
}
|
||||
|
|
|
@ -117,8 +117,9 @@ class Connection extends RawConnection {
|
|||
}
|
||||
|
||||
public function close($terminate = true) {
|
||||
if (is_resource($this->getInputStream())) {
|
||||
$this->write('close' . PHP_EOL);
|
||||
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);
|
||||
}
|
||||
parent::close($terminate);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Icewind\SMB\Wrapped;
|
||||
|
||||
use Icewind\SMB\ACL;
|
||||
use Icewind\SMB\IFileInfo;
|
||||
|
||||
class FileInfo implements IFileInfo {
|
||||
|
@ -35,19 +36,26 @@ class FileInfo implements IFileInfo {
|
|||
*/
|
||||
protected $mode;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
protected $aclCallback;
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param string $name
|
||||
* @param int $size
|
||||
* @param int $time
|
||||
* @param int $mode
|
||||
* @param callable $aclCallback
|
||||
*/
|
||||
public function __construct($path, $name, $size, $time, $mode) {
|
||||
public function __construct($path, $name, $size, $time, $mode, callable $aclCallback) {
|
||||
$this->path = $path;
|
||||
$this->name = $name;
|
||||
$this->size = $size;
|
||||
$this->time = $time;
|
||||
$this->mode = $mode;
|
||||
$this->aclCallback = $aclCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,4 +120,11 @@ class FileInfo implements IFileInfo {
|
|||
public function isArchived() {
|
||||
return (bool)($this->mode & IFileInfo::MODE_ARCHIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ACL[]
|
||||
*/
|
||||
public function getAcls(): array {
|
||||
return ($this->aclCallback)();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ class Parser {
|
|||
*/
|
||||
private $host;
|
||||
|
||||
// todo replace with static once <5.6 support is dropped
|
||||
// see error.h
|
||||
const EXCEPTION_MAP = [
|
||||
ErrorCodes::LogonFailure => AuthenticationException::class,
|
||||
|
@ -146,12 +145,12 @@ class Parser {
|
|||
}
|
||||
return [
|
||||
'mtime' => strtotime($data['write_time']),
|
||||
'mode' => hexdec(substr($data['attributes'], strpos($data['attributes'], '('), -1)),
|
||||
'mode' => hexdec(substr($data['attributes'], strpos($data['attributes'], '(') + 1, -1)),
|
||||
'size' => isset($data['stream']) ? (int)(explode(' ', $data['stream'])[1]) : 0
|
||||
];
|
||||
}
|
||||
|
||||
public function parseDir($output, $basePath) {
|
||||
public function parseDir($output, $basePath, callable $aclCallback) {
|
||||
//last line is used space
|
||||
array_pop($output);
|
||||
$regex = '/^\s*(.*?)\s\s\s\s+(?:([NDHARS]*)\s+)?([0-9]+)\s+(.*)$/';
|
||||
|
@ -163,7 +162,10 @@ class Parser {
|
|||
if ($name !== '.' and $name !== '..') {
|
||||
$mode = $this->parseMode($mode);
|
||||
$time = strtotime($time . ' ' . $this->timeZone);
|
||||
$content[] = new FileInfo($basePath . '/' . $name, $name, $size, $time, $mode);
|
||||
$path = $basePath . '/' . $name;
|
||||
$content[] = new FileInfo($path, $name, $size, $time, $mode, function () use ($aclCallback, $path) {
|
||||
return $aclCallback($path);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,18 +173,6 @@ class RawConnection {
|
|||
return;
|
||||
}
|
||||
if ($terminate) {
|
||||
// if for case that posix_ functions are not available
|
||||
if (function_exists('posix_kill')) {
|
||||
$status = proc_get_status($this->process);
|
||||
$ppid = $status['pid'];
|
||||
$pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $ppid`);
|
||||
foreach ($pids as $pid) {
|
||||
if (is_numeric($pid)) {
|
||||
//9 is the SIGKILL signal
|
||||
posix_kill($pid, 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
proc_terminate($this->process);
|
||||
}
|
||||
proc_close($this->process);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Icewind\SMB\Wrapped;
|
||||
|
||||
use Icewind\SMB\AbstractShare;
|
||||
use Icewind\SMB\ACL;
|
||||
use Icewind\SMB\Exception\ConnectionException;
|
||||
use Icewind\SMB\Exception\DependencyException;
|
||||
use Icewind\SMB\Exception\FileInUseException;
|
||||
|
@ -52,6 +53,8 @@ class Share extends AbstractShare {
|
|||
FileInfo::MODE_SYSTEM => 's'
|
||||
];
|
||||
|
||||
const EXEC_CMD = 'exec';
|
||||
|
||||
/**
|
||||
* @param IServer $server
|
||||
* @param string $name
|
||||
|
@ -75,7 +78,8 @@ class Share extends AbstractShare {
|
|||
|
||||
protected function getConnection() {
|
||||
$command = sprintf(
|
||||
'%s%s -t %s %s %s %s',
|
||||
'%s %s%s -t %s %s %s %s',
|
||||
self::EXEC_CMD,
|
||||
$this->system->getStdBufPath() ? $this->system->getStdBufPath() . ' -o0 ' : '',
|
||||
$this->system->getSmbclientPath(),
|
||||
$this->server->getOptions()->getTimeout(),
|
||||
|
@ -147,7 +151,9 @@ class Share extends AbstractShare {
|
|||
|
||||
$this->execute('cd /');
|
||||
|
||||
return $this->parser->parseDir($output, $path);
|
||||
return $this->parser->parseDir($output, $path, function ($path) {
|
||||
return $this->getAcls($path);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,7 +186,9 @@ class Share extends AbstractShare {
|
|||
$this->parseOutput($output, $path);
|
||||
}
|
||||
$stat = $this->parser->parseStat($output);
|
||||
return new FileInfo($path, basename($path), $stat['size'], $stat['mtime'], $stat['mode']);
|
||||
return new FileInfo($path, basename($path), $stat['size'], $stat['mtime'], $stat['mode'], function () use ($path) {
|
||||
return $this->getAcls($path);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -415,13 +423,13 @@ class Share extends AbstractShare {
|
|||
* @param string[] $lines
|
||||
* @param string $path
|
||||
*
|
||||
* @throws NotFoundException
|
||||
* @return bool
|
||||
* @throws \Icewind\SMB\Exception\AlreadyExistsException
|
||||
* @throws \Icewind\SMB\Exception\AccessDeniedException
|
||||
* @throws \Icewind\SMB\Exception\NotEmptyException
|
||||
* @throws \Icewind\SMB\Exception\InvalidTypeException
|
||||
* @throws \Icewind\SMB\Exception\Exception
|
||||
* @return bool
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
protected function parseOutput($lines, $path = '') {
|
||||
if (count($lines) === 0) {
|
||||
|
@ -464,6 +472,83 @@ class Share extends AbstractShare {
|
|||
return '"' . $path . '"';
|
||||
}
|
||||
|
||||
protected function getAcls($path) {
|
||||
$commandPath = $this->system->getSmbcAclsPath();
|
||||
if (!$commandPath) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$command = sprintf(
|
||||
'%s %s %s %s/%s %s',
|
||||
$commandPath,
|
||||
$this->getAuthFileArgument(),
|
||||
$this->server->getAuth()->getExtraCommandLineArguments(),
|
||||
escapeshellarg('//' . $this->server->getHost()),
|
||||
escapeshellarg($this->name),
|
||||
escapeshellarg($path)
|
||||
);
|
||||
$connection = new RawConnection($command);
|
||||
$connection->writeAuthentication($this->server->getAuth()->getUsername(), $this->server->getAuth()->getPassword());
|
||||
$connection->connect();
|
||||
if (!$connection->isValid()) {
|
||||
throw new ConnectionException($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;
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
unset($this->connection);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue