diff options
author | Robin Appelman <robin@icewind.nl> | 2017-03-25 00:34:02 +0300 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2017-03-25 00:34:02 +0300 |
commit | 4e3c8d2c4b898d8d1e0e70631d847aa2e6c4eb64 (patch) | |
tree | a7bc82ababf30cf5e447d03184dcdb1a4271e499 | |
parent | 75f963be94e6025cc4aeedf8c3c1e2bbbfdc5e48 (diff) |
filter opendir and accept glob patterns
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | appinfo/app.php | 3 | ||||
-rw-r--r-- | appinfo/info.xml | 3 | ||||
-rw-r--r-- | composer.json | 5 | ||||
-rw-r--r-- | lib/Wrapper/Exclude.php (renamed from wrapper/exclude.php) | 48 | ||||
-rw-r--r-- | lib/Wrapper/Manager.php (renamed from wrapper/manager.php) | 0 | ||||
-rw-r--r-- | tests/Wrapper/ExcludeTest.php | 114 |
7 files changed, 170 insertions, 5 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..987e2a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor diff --git a/appinfo/app.php b/appinfo/app.php index a043ba1..8b26925 100644 --- a/appinfo/app.php +++ b/appinfo/app.php @@ -20,6 +20,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + +require_once __DIR__ . '/../vendor/autoload.php'; + $manager = new \OCA\Files_ExcludeDirs\Wrapper\Manager(); OCP\Util::connectHook('OC_Filesystem', 'preSetup', $manager, 'setupStorageWrapper'); diff --git a/appinfo/info.xml b/appinfo/info.xml index 9ea20db..670875b 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -6,8 +6,9 @@ <licence>AGPL</licence> <author>Roeland Jago Douma</author> <version>0.0.1</version> + <namespace>Files_ExcludeDirs</namespace> <dependencies> - <owncloud min-version="9.2" max-version="9.2" /> + <nextcloud min-version="10" max-version="12" /> </dependencies> <types> <filesystem/> diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..70e258d --- /dev/null +++ b/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "webmozart/glob": "^4.1" + } +} diff --git a/wrapper/exclude.php b/lib/Wrapper/Exclude.php index a57c522..9caeb14 100644 --- a/wrapper/exclude.php +++ b/lib/Wrapper/Exclude.php @@ -20,9 +20,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ + namespace OCA\Files_ExcludeDirs\Wrapper; +use Icewind\Streams\IteratorDirectory; use OC\Files\Storage\Wrapper\Wrapper; +use Webmozart\Glob\Glob; class Exclude extends Wrapper { /** @@ -49,24 +52,61 @@ class Exclude extends Wrapper { return false; } - foreach ($this->exclude as $dir) { - if (strpos($path, $dir) !== false) { - return true; + foreach ($this->exclude as $rule) { + // glob requires all paths to be absolute so we put /'s in front of them + if (strpos($rule, '/') !== false) { + $rule = '/' . rtrim($rule, '/'); + return Glob::match('/' . $path, $rule); + } else { + $parts = explode('/', $path); + $rule = '/' . $rule; + foreach ($parts as $part) { + if (Glob::match('/' . $part, $rule)) { + return true; + } + } } } return false; } + public function file_exists($path) { + if ($this->excludedPath($path)) { + return false; + } + + return parent::file_exists($path); + } + /** * {@inheritdoc} */ public function opendir($path) { + $directoryIterator = $this->iterateDirectory($path); + + if ($directoryIterator) { + $filteredDirectory = new \CallbackFilterIterator($directoryIterator, function ($name) use ($path) { + return !$this->excludedPath($path . '/' . $name); + }); + $filteredDirectory->rewind(); + return IteratorDirectory::wrap($filteredDirectory); + } + + return false; + } + + private function iterateDirectory($path) { if ($this->excludedPath($path)) { return false; } - return $this->storage->opendir($path); + $handle = $this->storage->opendir($path); + while ($file = readdir($handle)) { + if ($file !== '.' && $file !== '..') { + yield $file; + } + } } /** diff --git a/wrapper/manager.php b/lib/Wrapper/Manager.php index 1cabea3..1cabea3 100644 --- a/wrapper/manager.php +++ b/lib/Wrapper/Manager.php diff --git a/tests/Wrapper/ExcludeTest.php b/tests/Wrapper/ExcludeTest.php new file mode 100644 index 0000000..c2aa8dd --- /dev/null +++ b/tests/Wrapper/ExcludeTest.php @@ -0,0 +1,114 @@ +<?php +/** + * @copyright Copyright (c) 2017 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 OCA\Files_ExcludeDirs\Test\Wrapper; + +use OC\Files\Storage\Local; +use OC\Files\Storage\Temporary; +use OCA\Files_ExcludeDirs\Wrapper\Exclude; +use Test\TestCase; + +\OC_App::loadApp('files_excludedirs'); + +class ExcludeTest extends TestCase { + /** @var Local */ + private $sourceStorage; + + protected function setUp() { + parent::setUp(); + + $this->sourceStorage = new Temporary(); + } + + private function setupParentFolders($path) { + $parts = explode('/', $path); + array_pop($parts); + $subPath = ''; + foreach ($parts as $part) { + $subPath .= $part; + $this->sourceStorage->mkdir($subPath); + $subPath .= '/'; + } + } + + public function testFileExistsProvider() { + return [ + ['foo', [], true], + ['foo', ['foo'], false], + ['bar', ['foo'], true], + ['bar/foo', ['foo'], false], + ['bar/foobar', ['foo'], true], + ['foo/foobar', ['foo'], false], + ['bar/foobar', ['foo*'], false], + ['bar/foobar', ['/foo*'], true], + ['bar/foo', ['bar/*'], false], + ['bar/foo/asd', ['bar/*'], true], + ['bar/foo/asd', ['bar/*/asd'], false], + ['bar/foo/qwerty/asd', ['bar/*/asd'], true], + ['bar/foo/qwerty/asd', ['bar/**/asd'], false], + ]; + } + + /** + * @dataProvider testFileExistsProvider + * + * @param string $path + * @param string[] $exclude + * @param bool $expected + */ + public function testFileExists($path, $exclude, $expected) { + $this->setupParentFolders($path); + $this->sourceStorage->file_put_contents($path, 'dummy'); + + + $storage = new Exclude([ + 'storage' => $this->sourceStorage, + 'exclude' => $exclude + ]); + + $this->assertEquals($expected, $storage->file_exists($path)); + } + + public function testOpenDir() { + $this->sourceStorage->mkdir('root'); + $this->sourceStorage->file_put_contents('root/asd', ''); + $this->sourceStorage->file_put_contents('root/bar', ''); + $this->sourceStorage->file_put_contents('root/foo', ''); + + $storage = new Exclude([ + 'storage' => $this->sourceStorage, + 'exclude' => [ + 'asd', + 'root/bar', + 'folder/foo' + ] + ]); + + $dh = $storage->opendir('root'); + + $content = []; + while ($file = readdir($dh)) { + $content[] = $file; + } + + $this->assertEquals(['foo'], $content); + } +} |