|
|
|
|
@ -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); |
|
|
|
|
|
|
|
|
|
|