From 61c9a065c2ba2473f4b2cc4f5060e7720d64d529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 16 Aug 2016 14:55:08 +0200 Subject: [PATCH 01/15] stat for root of a share does not work --- apps/files_external/lib/smb.php | 49 ++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index d9b85375b1bd..124abc3b7009 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -180,10 +180,57 @@ protected function formatInfo($info) { */ public function stat($path) { $this->log('enter: '.__FUNCTION__."($path)"); - $result = $this->formatInfo($this->getFileInfo($path)); + if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime doesn't work for shares + $result = [ + 'mtime' => $this->shareMTime(), + 'size' => 0, + 'type' => 'dir' + ]; + } else { + $result = $this->formatInfo($this->getFileInfo($path)); + } return $this->leave(__FUNCTION__, $result); } + /** + * get the best guess for the modification time of the share + * + * @return array the first element of the array is the calculated mtime for the folder, and + * the second is the list of readable files (the list contains the filename as key and the + * mtime for the file as value) + */ + private function shareMTime() { + $this->log('enter: '.__FUNCTION__, Util::DEBUG); + $files = $this->share->dir($this->root); + $result = 0; + foreach ($files as $fileInfo) { + if ($fileInfo->getMTime() > $result) { + $result = $fileInfo->getMTime(); + } + } + return $this->leave(__FUNCTION__, $result); + } + /** + * Check if the path is our root dir (not the smb one) + * + * @param string $path the path + * @return bool true if it's root, false if not + */ + private function isRootDir($path) { + $this->log('enter: '.__FUNCTION__."($path)", Util::DEBUG); + $result = $path === '' || $path === '/' || $path === '.'; + return $this->leave(__FUNCTION__, $result); + } + /** + * Check if our root points to a smb share + * + * @return bool true if our root points to a share false otherwise + */ + private function remoteIsShare() { + $this->log('enter: '.__FUNCTION__, Util::DEBUG); + $result = $this->share->getName() && (!$this->root || $this->root === '/'); + return $this->leave(__FUNCTION__, $result); + } /** * @param string $path * @return bool From e0c86965123f9f9afad0b57df0116df8e3912200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 16 Aug 2016 15:07:41 +0200 Subject: [PATCH 02/15] don't list hidden files --- apps/files_external/lib/smb.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 124abc3b7009..cce21b765317 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -150,9 +150,18 @@ protected function getFolderContents($path) { $this->log('enter: '.__FUNCTION__."($path)"); try { $path = $this->buildPath($path); - $result = $this->share->dir($path); - foreach ($result as $file) { - $this->statCache[$path . '/' . $file->getName()] = $file; + $result = []; + $children = $this->share->dir($path); + foreach ($children as $fileInfo) { + // check if the file is readable before adding it to the list + // can't use "isReadable" function here, use smb internals instead + if ($fileInfo->isHidden()) { + $this->log("{$fileInfo->getName()} isn't readable, skipping", Util::DEBUG); + } else { + $result[] = $fileInfo; + //remember entry so we can answer file_exists and filetype without a full stat + $this->statCache[$path . '/' . $fileInfo->getName()] = $fileInfo; + } } } catch (ConnectException $e) { $ex = new StorageNotAvailableException( From baec3a0c1301b31ea6355ea331e4920562dcf967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 16 Aug 2016 15:18:27 +0200 Subject: [PATCH 03/15] formatInfo should include type --- apps/files_external/lib/smb.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index cce21b765317..c60f096c6570 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -177,10 +177,15 @@ protected function getFolderContents($path) { * @return array */ protected function formatInfo($info) { - return array( + $result = [ 'size' => $info->getSize(), - 'mtime' => $info->getMTime() - ); + 'mtime' => $info->getMTime(), + ]; + if ($info->isDirectory()) { + $result['type'] = 'dir'; + } else { + $result['type'] = 'file'; + } } /** From f4051a13346d619d9e083baeb09a50ef1cd59bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 16 Aug 2016 15:22:45 +0200 Subject: [PATCH 04/15] overwrite target on rename --- apps/files_external/lib/smb.php | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index c60f096c6570..2a4ae53bcf4b 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -30,6 +30,7 @@ namespace OC\Files\Storage; +use Icewind\SMB\Exception\AlreadyExistsException; use Icewind\SMB\Exception\ConnectException; use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\ForbiddenException; @@ -188,6 +189,39 @@ protected function formatInfo($info) { } } + /** + * Rename the files + * + * @param string $source the old name of the path + * @param string $target the new name of the path + * @return bool true if the rename is successful, false otherwise + */ + public function rename($source, $target) { + $this->log("enter: rename('$source', '$target')", Util::DEBUG); + try { + $result = $this->share->rename($this->root . $source, $this->root . $target); + $this->removeFromCache($this->root . $source); + $this->removeFromCache($this->root . $target); + } catch (AlreadyExistsException $e) { + $this->unlink($target); + $result = $this->share->rename($this->root . $source, $this->root . $target); + $this->removeFromCache($this->root . $source); + $this->removeFromCache($this->root . $target); + $this->swallow(__FUNCTION__, $e); + } catch (\Exception $e) { + $this->swallow(__FUNCTION__, $e); + $result = false; + } + return $this->leave(__FUNCTION__, $result); + } + + private function removeFromCache($path) { + $path = trim($path, '/'); + // TODO The CappedCache does not really clear by prefix. It just clears all. + //$this->dirCache->clear($path); + $this->statCache->clear($path); + //$this->xattrCache->clear($path); + } /** * @param string $path * @return array From 5d11696c9ba2ec7fe289cd3f6808c9ebdf10e35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 16 Aug 2016 15:37:29 +0200 Subject: [PATCH 05/15] use stat to determine has updated --- apps/files_external/lib/smb.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 2a4ae53bcf4b..d1449ef4dfd3 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -318,10 +318,10 @@ public function unlink($path) { */ public function hasUpdated($path, $time) { $this->log('enter: '.__FUNCTION__."($path, $time)"); - if (!$path and $this->root == '/') { - // mtime doesn't work for shares, but giving the nature of the backend, - // doing a full update is still just fast enough - $result = true; + $stat = $this->stat($path); + if ($stat === false) { + Util::writeLog('wnd', 'hasUpdated failed -> storage not available', Util::ERROR); + throw $this->leave(__FUNCTION__, new StorageNotAvailableException()); } else { $actualTime = $this->filemtime($path); $result = $actualTime > $time; From b53de63a0b25a0c52557b04b26db3c2108b349ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 16 Aug 2016 15:43:55 +0200 Subject: [PATCH 06/15] stat now handles mtime for root shares, simplify hasUpdated --- apps/files_external/lib/smb.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index d1449ef4dfd3..324c663334a8 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -318,14 +318,8 @@ public function unlink($path) { */ public function hasUpdated($path, $time) { $this->log('enter: '.__FUNCTION__."($path, $time)"); - $stat = $this->stat($path); - if ($stat === false) { - Util::writeLog('wnd', 'hasUpdated failed -> storage not available', Util::ERROR); - throw $this->leave(__FUNCTION__, new StorageNotAvailableException()); - } else { - $actualTime = $this->filemtime($path); - $result = $actualTime > $time; - } + $actualTime = $this->filemtime($path); + $result = $actualTime > $time; return $this->leave(__FUNCTION__, $result); } From f95fc028830e7499eb2d2bda14449f60a02709f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Thu, 18 Aug 2016 15:06:23 +0200 Subject: [PATCH 07/15] move share check to getFileInfo --- apps/files_external/lib/smb.php | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 324c663334a8..75a46fc27c61 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -35,6 +35,7 @@ use Icewind\SMB\Exception\Exception; use Icewind\SMB\Exception\ForbiddenException; use Icewind\SMB\Exception\NotFoundException; +use Icewind\SMB\FileInfo; use Icewind\SMB\NativeServer; use Icewind\SMB\Server; use Icewind\Streams\CallbackWrapper; @@ -127,8 +128,12 @@ protected function getFileInfo($path) { try { $path = $this->buildPath($path); if (!isset($this->statCache[$path])) { - $this->log("stat fetching '{$this->root}$path'"); - $this->statCache[$path] = $this->share->stat($path); + if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime doesn't work for shares + $this->statCache[$path] = new FileInfo($path, '', 0, $this->shareMTime(), FileInfo::MODE_DIRECTORY); + } else { + $this->log("stat fetching '{$this->root}$path'"); + $this->statCache[$path] = $this->share->stat($path); + } } else { $this->log("stat cache hit for '$path'"); } @@ -228,24 +233,16 @@ private function removeFromCache($path) { */ public function stat($path) { $this->log('enter: '.__FUNCTION__."($path)"); - if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime doesn't work for shares - $result = [ - 'mtime' => $this->shareMTime(), - 'size' => 0, - 'type' => 'dir' - ]; - } else { - $result = $this->formatInfo($this->getFileInfo($path)); - } + $result = $this->formatInfo($this->getFileInfo($path)); return $this->leave(__FUNCTION__, $result); } /** * get the best guess for the modification time of the share + * NOTE: modification times do not bubble up the directory tree, basically + * we are just guessing a time * - * @return array the first element of the array is the calculated mtime for the folder, and - * the second is the list of readable files (the list contains the filename as key and the - * mtime for the file as value) + * @return int the calculated mtime for the folder */ private function shareMTime() { $this->log('enter: '.__FUNCTION__, Util::DEBUG); From 2565eaca9abcee2cd54cb0f4a37afb9dddd93c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Thu, 18 Aug 2016 15:26:23 +0200 Subject: [PATCH 08/15] always try stat, fake if forbidden, actually return the fileinfo array --- apps/files_external/lib/smb.php | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 75a46fc27c61..0050efb4477e 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -122,28 +122,33 @@ protected function buildPath($path) { * @param string $path * @return \Icewind\SMB\IFileInfo * @throws StorageNotAvailableException + * @throws ForbiddenException */ protected function getFileInfo($path) { $this->log('enter: '.__FUNCTION__."($path)"); - try { $path = $this->buildPath($path); if (!isset($this->statCache[$path])) { - if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime doesn't work for shares - $this->statCache[$path] = new FileInfo($path, '', 0, $this->shareMTime(), FileInfo::MODE_DIRECTORY); - } else { + try { $this->log("stat fetching '{$this->root}$path'"); $this->statCache[$path] = $this->share->stat($path); + } catch (ConnectException $e) { + $ex = new StorageNotAvailableException( + $e->getMessage(), $e->getCode(), $e); + $this->leave(__FUNCTION__, $ex); + throw $ex; + } catch (ForbiddenException $e) { + if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime may not work for share root + $this->log("faking stat for forbidden '{$this->root}|$path'"); + $this->statCache[$path] = new FileInfo($path, '', 0, $this->shareMTime(), FileInfo::MODE_DIRECTORY); + } else { + $this->leave(__FUNCTION__, $e); + throw $e; + } } } else { $this->log("stat cache hit for '$path'"); } $result = $this->statCache[$path]; - } catch (ConnectException $e) { - $ex = new StorageNotAvailableException( - $e->getMessage(), $e->getCode(), $e); - $this->leave(__FUNCTION__, $ex); - throw $ex; - } return $this->leave(__FUNCTION__, $result); } @@ -192,6 +197,7 @@ protected function formatInfo($info) { } else { $result['type'] = 'file'; } + return $result; } /** @@ -616,7 +622,7 @@ private function leave($function, $result) { .' message: '.$result->getMessage() .' trace: '.$result->getTraceAsString(), Util::DEBUG); } else { - Util::writeLog('wnd', "leave: $function, return ".json_encode($result), Util::DEBUG); + Util::writeLog('wnd', "leave: $function, return ".print_r($result, true), Util::DEBUG); } return $result; } From 717c521423a7d1ab10149ddc03c2d01a80778407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Thu, 18 Aug 2016 17:28:12 +0200 Subject: [PATCH 09/15] share root is always readable --- apps/files_external/lib/smb.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 0050efb4477e..da52cd70c511 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -129,8 +129,18 @@ protected function getFileInfo($path) { $path = $this->buildPath($path); if (!isset($this->statCache[$path])) { try { - $this->log("stat fetching '{$this->root}$path'"); + $this->log("stat fetching '{$this->root}|$path'"); $this->statCache[$path] = $this->share->stat($path); + if ($this->remoteIsShare() && $this->isRootDir($path) && $this->statCache[$path]->isHidden()) { + $this->log(" stat for '{$this->root}|$path'"); + // make root never hidden, may happen when accessing a shared drive (mode is 22, archived and readonly - neither is true ... whatever) + if ($this->statCache[$path]->isReadOnly()) { + $mode = FileInfo::MODE_DIRECTORY & FileInfo::MODE_READONLY; + } else { + $mode = FileInfo::MODE_DIRECTORY; + } + $this->statCache[$path] = new FileInfo($path, '', 0, $this->statCache[$path]->getMTime(), $mode); + } } catch (ConnectException $e) { $ex = new StorageNotAvailableException( $e->getMessage(), $e->getCode(), $e); @@ -622,7 +632,7 @@ private function leave($function, $result) { .' message: '.$result->getMessage() .' trace: '.$result->getTraceAsString(), Util::DEBUG); } else { - Util::writeLog('wnd', "leave: $function, return ".print_r($result, true), Util::DEBUG); + Util::writeLog('wnd', "leave: $function, return ".json_encode($result, true), Util::DEBUG); } return $result; } From d253b6dfab3d7699ce425efe7c12417eb02493b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Mon, 22 Aug 2016 14:55:50 +0200 Subject: [PATCH 10/15] do not overwrite stat cache with plain array --- apps/files_external/lib/smb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index da52cd70c511..86ea6593ff31 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -413,7 +413,7 @@ public function rmdir($path) { $this->log('enter: '.__FUNCTION__."($path)"); $result = false; try { - $this->statCache = array(); + $this->removeFromCache($path); $content = $this->share->dir($this->buildPath($path)); foreach ($content as $file) { if ($file->isDirectory()) { From 1ac6f4f811a769b38b9a0c94c7c109e39429148a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Tue, 23 Aug 2016 12:19:30 +0200 Subject: [PATCH 11/15] fix test execution due to connection limit --- apps/files_external/lib/smb.php | 15 ++++++++++----- apps/files_external/tests/backends/smb.php | 4 +++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 86ea6593ff31..4b6a7f4b04b5 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -129,10 +129,10 @@ protected function getFileInfo($path) { $path = $this->buildPath($path); if (!isset($this->statCache[$path])) { try { - $this->log("stat fetching '{$this->root}|$path'"); + $this->log("stat fetching '$path'"); $this->statCache[$path] = $this->share->stat($path); if ($this->remoteIsShare() && $this->isRootDir($path) && $this->statCache[$path]->isHidden()) { - $this->log(" stat for '{$this->root}|$path'"); + $this->log(" stat for '$path'"); // make root never hidden, may happen when accessing a shared drive (mode is 22, archived and readonly - neither is true ... whatever) if ($this->statCache[$path]->isReadOnly()) { $mode = FileInfo::MODE_DIRECTORY & FileInfo::MODE_READONLY; @@ -492,8 +492,7 @@ public function mkdir($path) { $result = false; $path = $this->buildPath($path); try { - $this->share->mkdir($path); - $result = true; + $result = $this->share->mkdir($path); } catch (ConnectException $e) { $ex = new StorageNotAvailableException( $e->getMessage(), $e->getCode(), $e); @@ -594,7 +593,6 @@ public function test() { return $this->leave(__FUNCTION__, $result); } - /** * @param string $message * @param int $level @@ -645,4 +643,11 @@ private function swallow($function, \Exception $exception) { .' trace: '.$exception->getTraceAsString(), Util::DEBUG); } } + + /** + * immediately close / free connection + */ + public function __destruct() { + unset($this->share); + } } diff --git a/apps/files_external/tests/backends/smb.php b/apps/files_external/tests/backends/smb.php index f9a377c271b4..bbe218979b4a 100644 --- a/apps/files_external/tests/backends/smb.php +++ b/apps/files_external/tests/backends/smb.php @@ -47,12 +47,14 @@ protected function setUp() { } $config['root'] .= $id; //make sure we have an new empty folder to work in $this->instance = new \OC\Files\Storage\SMB($config); - $this->instance->mkdir('/'); + $this->assertTrue($this->instance->mkdir('/')); } protected function tearDown() { if ($this->instance) { $this->instance->rmdir(''); + // force disconnect of the client + unset($this->instance); } parent::tearDown(); From 1ef2059ff6c9e2c50a0a955d63eedd93f28b77f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 24 Aug 2016 10:03:40 +0200 Subject: [PATCH 12/15] add dir based stat fallback --- apps/files_external/lib/smb.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 4b6a7f4b04b5..0af88c527072 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -44,6 +44,7 @@ use OC\Files\Filesystem; use OCP\Files\StorageNotAvailableException; use OCP\Util; +use Sabre\DAV\Exception\NotFound; class SMB extends Common { /** @@ -130,7 +131,22 @@ protected function getFileInfo($path) { if (!isset($this->statCache[$path])) { try { $this->log("stat fetching '$path'"); - $this->statCache[$path] = $this->share->stat($path); + try { + $this->statCache[$path] = $this->share->stat($path); + } catch (NotFoundException $e) { + $this->log("stat for '$path' failed, trying to read parent dir"); + $infos = $this->share->dir(dirname($path)); + foreach ($infos as $fileInfo) { + if ($fileInfo->getName() === basename($path)) { + $this->statCache[$path] = $fileInfo; + break; + } + } + if (empty($this->statCache[$path])) { + $this->leave(__FUNCTION__, $e); + throw $e; + } + } if ($this->remoteIsShare() && $this->isRootDir($path) && $this->statCache[$path]->isHidden()) { $this->log(" stat for '$path'"); // make root never hidden, may happen when accessing a shared drive (mode is 22, archived and readonly - neither is true ... whatever) From 93229e76fdfd5fbaa2bd02a9e6bc7fc5190a3917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 24 Aug 2016 12:45:18 +0200 Subject: [PATCH 13/15] fix return values for smbclient backend see https://github.com/icewind1991/SMB/commit/6e544f617cc271e34d41ea28dd7714a9b1ff75f1 --- apps/files_external/3rdparty/icewind/smb/src/Share.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_external/3rdparty/icewind/smb/src/Share.php b/apps/files_external/3rdparty/icewind/smb/src/Share.php index 694bd30bd0df..fe253a94c2f0 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Share.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Share.php @@ -370,7 +370,7 @@ protected function execute($command) { * @return bool */ protected function parseOutput($lines, $path = '') { - $this->parser->checkForError($lines, $path); + return $this->parser->checkForError($lines, $path); } /** From 185ce22f517980ef30a68c76925b5ef0a7a9d7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 24 Aug 2016 13:07:44 +0200 Subject: [PATCH 14/15] allow unhiding root folder in subfolder of share --- apps/files_external/lib/smb.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 0af88c527072..35e684e5aa9f 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -124,6 +124,7 @@ protected function buildPath($path) { * @return \Icewind\SMB\IFileInfo * @throws StorageNotAvailableException * @throws ForbiddenException + * @throws NotFoundException */ protected function getFileInfo($path) { $this->log('enter: '.__FUNCTION__."($path)"); @@ -147,8 +148,8 @@ protected function getFileInfo($path) { throw $e; } } - if ($this->remoteIsShare() && $this->isRootDir($path) && $this->statCache[$path]->isHidden()) { - $this->log(" stat for '$path'"); + if ($this->isRootDir($path) && $this->statCache[$path]->isHidden()) { + $this->log("unhiding stat for '$path'"); // make root never hidden, may happen when accessing a shared drive (mode is 22, archived and readonly - neither is true ... whatever) if ($this->statCache[$path]->isReadOnly()) { $mode = FileInfo::MODE_DIRECTORY & FileInfo::MODE_READONLY; @@ -164,7 +165,7 @@ protected function getFileInfo($path) { throw $ex; } catch (ForbiddenException $e) { if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime may not work for share root - $this->log("faking stat for forbidden '{$this->root}|$path'"); + $this->log("faking stat for forbidden '$path'"); $this->statCache[$path] = new FileInfo($path, '', 0, $this->shareMTime(), FileInfo::MODE_DIRECTORY); } else { $this->leave(__FUNCTION__, $e); From ebf8be10cc199ce4b046af663705a56b569850e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Wed, 24 Aug 2016 14:12:40 +0200 Subject: [PATCH 15/15] trust libsmbclient on stat, only do dir fallback for smbclient --- apps/files_external/lib/smb.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index 35e684e5aa9f..91a84f9c42ec 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -38,13 +38,13 @@ use Icewind\SMB\FileInfo; use Icewind\SMB\NativeServer; use Icewind\SMB\Server; +use Icewind\SMB\Share; use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use OC\Cache\CappedMemoryCache; use OC\Files\Filesystem; use OCP\Files\StorageNotAvailableException; use OCP\Util; -use Sabre\DAV\Exception\NotFound; class SMB extends Common { /** @@ -135,15 +135,22 @@ protected function getFileInfo($path) { try { $this->statCache[$path] = $this->share->stat($path); } catch (NotFoundException $e) { - $this->log("stat for '$path' failed, trying to read parent dir"); - $infos = $this->share->dir(dirname($path)); - foreach ($infos as $fileInfo) { - if ($fileInfo->getName() === basename($path)) { - $this->statCache[$path] = $fileInfo; - break; + if ($this->share instanceof Share) { + // smbclient may have problems with the allinfo cmd + $this->log("stat for '$path' failed, trying to read parent dir"); + $infos = $this->share->dir(dirname($path)); + foreach ($infos as $fileInfo) { + if ($fileInfo->getName() === basename($path)) { + $this->statCache[$path] = $fileInfo; + break; + } } - } - if (empty($this->statCache[$path])) { + if (empty($this->statCache[$path])) { + $this->leave(__FUNCTION__, $e); + throw $e; + } + } else { + // trust the results of libsmb $this->leave(__FUNCTION__, $e); throw $e; }