]> source.dussan.org Git - nextcloud-server.git/commitdiff
update icewind/smb to 3.2.1 20207/head
authorRobin Appelman <robin@icewind.nl>
Fri, 27 Mar 2020 15:57:55 +0000 (16:57 +0100)
committerRobin Appelman <robin@icewind.nl>
Fri, 27 Mar 2020 15:57:55 +0000 (16:57 +0100)
Signed-off-by: Robin Appelman <robin@icewind.nl>
21 files changed:
apps/files_external/3rdparty/composer.json
apps/files_external/3rdparty/composer.lock
apps/files_external/3rdparty/composer/autoload_classmap.php
apps/files_external/3rdparty/composer/autoload_real.php
apps/files_external/3rdparty/composer/autoload_static.php
apps/files_external/3rdparty/composer/installed.json
apps/files_external/3rdparty/icewind/smb/.gitignore
apps/files_external/3rdparty/icewind/smb/README.md
apps/files_external/3rdparty/icewind/smb/composer.json
apps/files_external/3rdparty/icewind/smb/src/ACL.php [new file with mode: 0644]
apps/files_external/3rdparty/icewind/smb/src/IFileInfo.php
apps/files_external/3rdparty/icewind/smb/src/ISystem.php
apps/files_external/3rdparty/icewind/smb/src/Native/NativeFileInfo.php
apps/files_external/3rdparty/icewind/smb/src/Native/NativeShare.php
apps/files_external/3rdparty/icewind/smb/src/Native/NativeState.php
apps/files_external/3rdparty/icewind/smb/src/System.php
apps/files_external/3rdparty/icewind/smb/src/Wrapped/Connection.php
apps/files_external/3rdparty/icewind/smb/src/Wrapped/FileInfo.php
apps/files_external/3rdparty/icewind/smb/src/Wrapped/Parser.php
apps/files_external/3rdparty/icewind/smb/src/Wrapped/RawConnection.php
apps/files_external/3rdparty/icewind/smb/src/Wrapped/Share.php

index 6c23067c4a5ebbff420c8ae242ea672d8c0a8167..9cf429eb5c29087cbe5accd6436a8bdf228ebc34 100644 (file)
@@ -9,6 +9,6 @@
        },
        "require": {
                "icewind/streams": "0.7.1",
-               "icewind/smb": "3.1.1"
+               "icewind/smb": "3.2.1"
        }
 }
index 491b73fa1f40f0747b2aac5956c2e676e8249a99..c486854d6a92cc6602fc74509c3bb8d3247fffb6 100644 (file)
@@ -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"
 }
index 9eb83e893bd7ef198aa7fb9a01d158fe3456d41c..5b0c682cbcedb449b46c8a9e49763cb6af1ee4bc 100644 (file)
@@ -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',
index 4ac68127fea9d80e40d94395d03be3ab96b6540f..36857d406cd6b36123dcfd32994628ca72887743 100644 (file)
@@ -13,6 +13,9 @@ class ComposerAutoloaderInit98fe9b281934250b3a93f69a5ce843b3
         }
     }
 
+    /**
+     * @return \Composer\Autoload\ClassLoader
+     */
     public static function getLoader()
     {
         if (null !== self::$loader) {
index eb2329b2b05554cd86f11e3911c1f2053d0932ba..b8eb6ebbfe8af1813efebdbd324d834dbadbb985 100644 (file)
@@ -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',
index 18ee9e5431fddff11b05b298058b3efebc05374c..e3609f5af4e28a8d192ee2961191daac4a9fc584 100644 (file)
@@ -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": {
index 966ac1bcbe1c73c117ddebee21660c7d1b84bdec..17e19f04f56cb82ac09d05fda7857330cef829b1 100644 (file)
@@ -2,4 +2,5 @@
 vendor
 composer.lock
 .php_cs.cache
-
+listen.php
+test.php
index 4c20b1412af60742c9a30087d881e68827ebe4c1..6a35e736acbbc16373b7c70e922cbfe25a7690d6 100644 (file)
@@ -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');
index 78375c4df48cd4316f6f285a679c9613d89efd50..8ec551c7340f4a871f9292f098158a2f3eb80d68 100644 (file)
@@ -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"         : {
diff --git a/apps/files_external/3rdparty/icewind/smb/src/ACL.php b/apps/files_external/3rdparty/icewind/smb/src/ACL.php
new file mode 100644 (file)
index 0000000..bdb7725
--- /dev/null
@@ -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;
+       }
+}
index ae8acd3a3dbad1787d2908928c9b7468414c7b7f..3411d498d787335c81ec7912ef3b063ce1fa561e 100644 (file)
@@ -65,4 +65,9 @@ interface IFileInfo {
         * @return bool
         */
        public function isArchived();
+
+       /**
+        * @return ACL[]
+        */
+       public function getAcls(): array;
 }
index 7740c98d97e01d73702324b55c0dd67259ac1e08..099946107164254706ecfda921db44a55794da32 100644 (file)
@@ -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
         *
index 904318907f2c7b2c8c79322f1e790de9fbc62d1a..24344e6f0df66cb2edff03b99fba6b1249c97f01 100644 (file)
@@ -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 $stat['change_time'];
        }
 
        /**
-        * @return bool
+        * @return int
         */
-       public function isDirectory() {
-               $stat = $this->stat();
-               return !($stat['mode'] & self::MODE_FILE);
+       protected function getMode() {
+               return $this->stat()['mode'];
        }
 
        /**
-        * @return int
+        * @return bool
         */
-       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;
+       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;
+       }
 }
index 1a33f4b0d367b0337780b63d68b4d7120b4458a7..26e7adb019db8cf095cb35ffbd881b975bfae30c 100644 (file)
@@ -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);
        }
 
index 5ab129cbfd3bcbf313da8ecd592ba7d8067954df..0792b2f9d7f11f63f5a4a53be8272f69e2d909b9 100644 (file)
@@ -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,
index 3428dd87cd6843e018e7e897d684786a76cbaf4d..0e41ee032d6c7caa8549066a269e75bf5dd38907 100644 (file)
@@ -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');
        }
index 830f6fb17b084360f89d48daab1b4a9e4e9c6a13..347b63db110215e79a4608bdb9ebdfad4c1b19b9 100644 (file)
@@ -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);
        }
index 094e665a93563d3ef5da9ff42a96f1f9cc22116c..a310a6bc91321f8e04244b6ccc1a28fe298bc59e 100644 (file)
@@ -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)();
+       }
 }
index 9eee686c0bac87d6a328e259e43b5a2fb4435598..a28432e43194c313c695879c1360eb0098e799ce 100644 (file)
@@ -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);
+                                       });
                                }
                        }
                }
index f29cf60eb6649d1d5acac79890f504ae0fc7fd5a..3a114af5e4f12701b76ca46d100c83b9ff316088 100644 (file)
@@ -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);
index 5a79c49fecf551bec53b605bb0b0c09c742b1765..e0df1f60326689783cd469bd322ec973678ac8e5 100644 (file)
@@ -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;
@@ -55,6 +56,8 @@ class Share extends AbstractShare {
                FileInfo::MODE_SYSTEM   => 's'
        ];
 
+       const EXEC_CMD = 'exec';
+
        /**
         * @param IServer $server
         * @param string $name
@@ -78,7 +81,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(),
@@ -150,7 +154,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);
+               });
        }
 
        /**
@@ -183,7 +189,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);
+               });
        }
 
        /**
@@ -418,13 +426,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) {
@@ -467,6 +475,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);
        }