Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Petry <vincent@nextcloud.com>2021-03-15 19:45:30 +0300
committerGitHub <noreply@github.com>2021-03-15 19:45:30 +0300
commite559afb8d409f75fdf9a216428d858d08aa1ee03 (patch)
treeafea41e1f4cf5f9f25070e819ef9637267c63ec0 /lib/private/Files/Cache
parentf512705f8f3ba7ff676b139bbfc00dcf6d277bd1 (diff)
parent6ecf33bfe7ef719cd979de5b29fc1da02e255632 (diff)
Merge pull request #25136 from nextcloud/cachejail-search-filter
do cachejail search filtering in sql
Diffstat (limited to 'lib/private/Files/Cache')
-rw-r--r--lib/private/Files/Cache/Cache.php2
-rw-r--r--lib/private/Files/Cache/QuerySearchHelper.php5
-rw-r--r--lib/private/Files/Cache/Wrapper/CacheJail.php113
3 files changed, 103 insertions, 17 deletions
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index 2513abd525f..840523c1890 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -121,7 +121,7 @@ class Cache implements ICache {
$this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
}
- private function getQueryBuilder() {
+ protected function getQueryBuilder() {
return new CacheQueryBuilder(
$this->connection,
\OC::$server->getSystemConfig(),
diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php
index da1f5729d3c..fc4b582cbce 100644
--- a/lib/private/Files/Cache/QuerySearchHelper.php
+++ b/lib/private/Files/Cache/QuerySearchHelper.php
@@ -166,6 +166,9 @@ class QuerySearchHelper {
$field = 'tag.category';
} elseif ($field === 'fileid') {
$field = 'file.fileid';
+ } elseif ($field === 'path' && $type === ISearchComparison::COMPARE_EQUAL) {
+ $field = 'path_hash';
+ $value = md5((string)$value);
}
return [$field, $value, $type];
}
@@ -175,6 +178,7 @@ class QuerySearchHelper {
'mimetype' => 'string',
'mtime' => 'integer',
'name' => 'string',
+ 'path' => 'string',
'size' => 'integer',
'tagname' => 'string',
'favorite' => 'boolean',
@@ -184,6 +188,7 @@ class QuerySearchHelper {
'mimetype' => ['eq', 'like'],
'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'],
'name' => ['eq', 'like'],
+ 'path' => ['eq', 'like'],
'size' => ['eq', 'gt', 'lt', 'gte', 'lte'],
'tagname' => ['eq', 'like'],
'favorite' => ['eq'],
diff --git a/lib/private/Files/Cache/Wrapper/CacheJail.php b/lib/private/Files/Cache/Wrapper/CacheJail.php
index 6c1c17be028..fe3124301ba 100644
--- a/lib/private/Files/Cache/Wrapper/CacheJail.php
+++ b/lib/private/Files/Cache/Wrapper/CacheJail.php
@@ -29,8 +29,13 @@
namespace OC\Files\Cache\Wrapper;
use OC\Files\Cache\Cache;
+use OC\Files\Search\SearchBinaryOperator;
+use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchQuery;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\Search\ISearchBinaryOperator;
+use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchQuery;
/**
@@ -41,6 +46,7 @@ class CacheJail extends CacheWrapper {
* @var string
*/
protected $root;
+ protected $unjailedRoot;
/**
* @param \OCP\Files\Cache\ICache $cache
@@ -49,12 +55,29 @@ class CacheJail extends CacheWrapper {
public function __construct($cache, $root) {
parent::__construct($cache);
$this->root = $root;
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
+
+ if ($cache instanceof CacheJail) {
+ $this->unjailedRoot = $cache->getSourcePath($root);
+ } else {
+ $this->unjailedRoot = $root;
+ }
}
protected function getRoot() {
return $this->root;
}
+ /**
+ * Get the root path with any nested jails resolved
+ *
+ * @return string
+ */
+ protected function getGetUnjailedRoot() {
+ return $this->unjailedRoot;
+ }
+
protected function getSourcePath($path) {
if ($path === '') {
return $this->getRoot();
@@ -65,16 +88,20 @@ class CacheJail extends CacheWrapper {
/**
* @param string $path
+ * @param null|string $root
* @return null|string the jailed path or null if the path is outside the jail
*/
- protected function getJailedPath($path) {
- if ($this->getRoot() === '') {
+ protected function getJailedPath(string $path, string $root = null) {
+ if ($root === null) {
+ $root = $this->getRoot();
+ }
+ if ($root === '') {
return $path;
}
- $rootLength = strlen($this->getRoot()) + 1;
- if ($path === $this->getRoot()) {
+ $rootLength = strlen($root) + 1;
+ if ($path === $root) {
return '';
- } elseif (substr($path, 0, $rootLength) === $this->getRoot() . '/') {
+ } elseif (substr($path, 0, $rootLength) === $root . '/') {
return substr($path, $rootLength);
} else {
return null;
@@ -92,11 +119,6 @@ class CacheJail extends CacheWrapper {
return $entry;
}
- protected function filterCacheEntry($entry) {
- $rootLength = strlen($this->getRoot()) + 1;
- return $rootLength === 1 || ($entry['path'] === $this->getRoot()) || (substr($entry['path'], 0, $rootLength) === $this->getRoot() . '/');
- }
-
/**
* get the stored metadata of a file or folder
*
@@ -209,9 +231,10 @@ class CacheJail extends CacheWrapper {
}
private function formatSearchResults($results) {
- $results = array_filter($results, [$this, 'filterCacheEntry']);
- $results = array_values($results);
- return array_map([$this, 'formatCacheEntry'], $results);
+ return array_map(function ($entry) {
+ $entry['path'] = $this->getJailedPath($entry['path'], $this->getGetUnjailedRoot());
+ return $entry;
+ }, $results);
}
/**
@@ -221,7 +244,29 @@ class CacheJail extends CacheWrapper {
* @return array an array of file data
*/
public function search($pattern) {
- $results = $this->getCache()->search($pattern);
+ // normalize pattern
+ $pattern = $this->normalize($pattern);
+
+ if ($pattern === '%%') {
+ return [];
+ }
+
+ $query = $this->getQueryBuilder();
+ $query->selectFileCache()
+ ->whereStorageId()
+ ->andWhere($query->expr()->orX(
+ $query->expr()->like('path', $query->createNamedParameter($this->getGetUnjailedRoot() . '/%')),
+ $query->expr()->eq('path_hash', $query->createNamedParameter(md5($this->getGetUnjailedRoot()))),
+ ))
+ ->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern)));
+
+ $result = $query->execute();
+ $files = $result->fetchAll();
+ $result->closeCursor();
+
+ $results = array_map(function (array $data) {
+ return self::cacheEntryFromData($data, $this->mimetypeLoader);
+ }, $files);
return $this->formatSearchResults($results);
}
@@ -232,12 +277,48 @@ class CacheJail extends CacheWrapper {
* @return array
*/
public function searchByMime($mimetype) {
- $results = $this->getCache()->searchByMime($mimetype);
+ $mimeId = $this->mimetypeLoader->getId($mimetype);
+
+ $query = $this->getQueryBuilder();
+ $query->selectFileCache()
+ ->whereStorageId()
+ ->andWhere($query->expr()->orX(
+ $query->expr()->like('path', $query->createNamedParameter($this->getGetUnjailedRoot() . '/%')),
+ $query->expr()->eq('path_hash', $query->createNamedParameter(md5($this->getGetUnjailedRoot()))),
+ ));
+
+ if (strpos($mimetype, '/')) {
+ $query->andWhere($query->expr()->eq('mimetype', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
+ } else {
+ $query->andWhere($query->expr()->eq('mimepart', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
+ }
+
+ $result = $query->execute();
+ $files = $result->fetchAll();
+ $result->closeCursor();
+
+ $results = array_map(function (array $data) {
+ return self::cacheEntryFromData($data, $this->mimetypeLoader);
+ }, $files);
return $this->formatSearchResults($results);
}
public function searchQuery(ISearchQuery $query) {
- $simpleQuery = new SearchQuery($query->getSearchOperation(), 0, 0, $query->getOrder(), $query->getUser());
+ $prefixFilter = new SearchComparison(
+ ISearchComparison::COMPARE_LIKE,
+ 'path',
+ $this->getGetUnjailedRoot() . '/%'
+ );
+ $rootFilter = new SearchComparison(
+ ISearchComparison::COMPARE_EQUAL,
+ 'path',
+ $this->getGetUnjailedRoot()
+ );
+ $operation = new SearchBinaryOperator(
+ ISearchBinaryOperator::OPERATOR_AND,
+ [new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, [$prefixFilter, $rootFilter]) , $query->getSearchOperation()]
+ );
+ $simpleQuery = new SearchQuery($operation, 0, 0, $query->getOrder(), $query->getUser());
$results = $this->getCache()->searchQuery($simpleQuery);
$results = $this->formatSearchResults($results);