3030namespace OC \Files \Cache \Wrapper ;
3131
3232use OC \Files \Cache \Cache ;
33+ use OC \Files \Search \SearchBinaryOperator ;
34+ use OC \Files \Search \SearchComparison ;
3335use OC \Files \Search \SearchQuery ;
36+ use OCP \DB \QueryBuilder \IQueryBuilder ;
3437use OCP \Files \Cache \ICacheEntry ;
38+ use OCP \Files \Search \ISearchBinaryOperator ;
39+ use OCP \Files \Search \ISearchComparison ;
3540use OCP \Files \Search \ISearchQuery ;
3641
3742/**
@@ -42,6 +47,7 @@ class CacheJail extends CacheWrapper {
4247 * @var string
4348 */
4449 protected $ root ;
50+ protected $ unjailedRoot ;
4551
4652 /**
4753 * @param \OCP\Files\Cache\ICache $cache
@@ -50,12 +56,29 @@ class CacheJail extends CacheWrapper {
5056 public function __construct ($ cache , $ root ) {
5157 parent ::__construct ($ cache );
5258 $ this ->root = $ root ;
59+ $ this ->connection = \OC ::$ server ->getDatabaseConnection ();
60+ $ this ->mimetypeLoader = \OC ::$ server ->getMimeTypeLoader ();
61+
62+ if ($ cache instanceof CacheJail) {
63+ $ this ->unjailedRoot = $ cache ->getSourcePath ($ root );
64+ } else {
65+ $ this ->unjailedRoot = $ root ;
66+ }
5367 }
5468
5569 protected function getRoot () {
5670 return $ this ->root ;
5771 }
5872
73+ /**
74+ * Get the root path with any nested jails resolved
75+ *
76+ * @return string
77+ */
78+ protected function getGetUnjailedRoot () {
79+ return $ this ->unjailedRoot ;
80+ }
81+
5982 protected function getSourcePath ($ path ) {
6083 if ($ path === '' ) {
6184 return $ this ->getRoot ();
@@ -66,16 +89,20 @@ protected function getSourcePath($path) {
6689
6790 /**
6891 * @param string $path
92+ * @param null|string $root
6993 * @return null|string the jailed path or null if the path is outside the jail
7094 */
71- protected function getJailedPath ($ path ) {
72- if ($ this ->getRoot () === '' ) {
95+ protected function getJailedPath (string $ path , string $ root = null ) {
96+ if ($ root === null ) {
97+ $ root = $ this ->getRoot ();
98+ }
99+ if ($ root === '' ) {
73100 return $ path ;
74101 }
75- $ rootLength = strlen ($ this -> getRoot () ) + 1 ;
76- if ($ path === $ this -> getRoot () ) {
102+ $ rootLength = strlen ($ root ) + 1 ;
103+ if ($ path === $ root ) {
77104 return '' ;
78- } elseif (substr ($ path , 0 , $ rootLength ) === $ this -> getRoot () . '/ ' ) {
105+ } elseif (substr ($ path , 0 , $ rootLength ) === $ root . '/ ' ) {
79106 return substr ($ path , $ rootLength );
80107 } else {
81108 return null ;
@@ -93,11 +120,6 @@ protected function formatCacheEntry($entry) {
93120 return $ entry ;
94121 }
95122
96- protected function filterCacheEntry ($ entry ) {
97- $ rootLength = strlen ($ this ->getRoot ()) + 1 ;
98- return $ rootLength === 1 || ($ entry ['path ' ] === $ this ->getRoot ()) || (substr ($ entry ['path ' ], 0 , $ rootLength ) === $ this ->getRoot () . '/ ' );
99- }
100-
101123 /**
102124 * get the stored metadata of a file or folder
103125 *
@@ -210,9 +232,10 @@ public function getStatus($file) {
210232 }
211233
212234 private function formatSearchResults ($ results ) {
213- $ results = array_filter ($ results , [$ this , 'filterCacheEntry ' ]);
214- $ results = array_values ($ results );
215- return array_map ([$ this , 'formatCacheEntry ' ], $ results );
235+ return array_map (function ($ entry ) {
236+ $ entry ['path ' ] = $ this ->getJailedPath ($ entry ['path ' ], $ this ->getGetUnjailedRoot ());
237+ return $ entry ;
238+ }, $ results );
216239 }
217240
218241 /**
@@ -222,7 +245,29 @@ private function formatSearchResults($results) {
222245 * @return array an array of file data
223246 */
224247 public function search ($ pattern ) {
225- $ results = $ this ->getCache ()->search ($ pattern );
248+ // normalize pattern
249+ $ pattern = $ this ->normalize ($ pattern );
250+
251+ if ($ pattern === '%% ' ) {
252+ return [];
253+ }
254+
255+ $ query = $ this ->getQueryBuilder ();
256+ $ query ->selectFileCache ()
257+ ->whereStorageId ()
258+ ->andWhere ($ query ->expr ()->orX (
259+ $ query ->expr ()->like ('path ' , $ query ->createNamedParameter ($ this ->getGetUnjailedRoot () . '/% ' )),
260+ $ query ->expr ()->eq ('path_hash ' , $ query ->createNamedParameter (md5 ($ this ->getGetUnjailedRoot ())))
261+ ))
262+ ->andWhere ($ query ->expr ()->iLike ('name ' , $ query ->createNamedParameter ($ pattern )));
263+
264+ $ result = $ query ->execute ();
265+ $ files = $ result ->fetchAll ();
266+ $ result ->closeCursor ();
267+
268+ $ results = array_map (function (array $ data ) {
269+ return self ::cacheEntryFromData ($ data , $ this ->mimetypeLoader );
270+ }, $ files );
226271 return $ this ->formatSearchResults ($ results );
227272 }
228273
@@ -233,12 +278,48 @@ public function search($pattern) {
233278 * @return array
234279 */
235280 public function searchByMime ($ mimetype ) {
236- $ results = $ this ->getCache ()->searchByMime ($ mimetype );
281+ $ mimeId = $ this ->mimetypeLoader ->getId ($ mimetype );
282+
283+ $ query = $ this ->getQueryBuilder ();
284+ $ query ->selectFileCache ()
285+ ->whereStorageId ()
286+ ->andWhere ($ query ->expr ()->orX (
287+ $ query ->expr ()->like ('path ' , $ query ->createNamedParameter ($ this ->getGetUnjailedRoot () . '/% ' )),
288+ $ query ->expr ()->eq ('path_hash ' , $ query ->createNamedParameter (md5 ($ this ->getGetUnjailedRoot ())))
289+ ));
290+
291+ if (strpos ($ mimetype , '/ ' )) {
292+ $ query ->andWhere ($ query ->expr ()->eq ('mimetype ' , $ query ->createNamedParameter ($ mimeId , IQueryBuilder::PARAM_INT )));
293+ } else {
294+ $ query ->andWhere ($ query ->expr ()->eq ('mimepart ' , $ query ->createNamedParameter ($ mimeId , IQueryBuilder::PARAM_INT )));
295+ }
296+
297+ $ result = $ query ->execute ();
298+ $ files = $ result ->fetchAll ();
299+ $ result ->closeCursor ();
300+
301+ $ results = array_map (function (array $ data ) {
302+ return self ::cacheEntryFromData ($ data , $ this ->mimetypeLoader );
303+ }, $ files );
237304 return $ this ->formatSearchResults ($ results );
238305 }
239306
240307 public function searchQuery (ISearchQuery $ query ) {
241- $ simpleQuery = new SearchQuery ($ query ->getSearchOperation (), 0 , 0 , $ query ->getOrder (), $ query ->getUser ());
308+ $ prefixFilter = new SearchComparison (
309+ ISearchComparison::COMPARE_LIKE ,
310+ 'path ' ,
311+ $ this ->getGetUnjailedRoot () . '/% '
312+ );
313+ $ rootFilter = new SearchComparison (
314+ ISearchComparison::COMPARE_EQUAL ,
315+ 'path ' ,
316+ $ this ->getGetUnjailedRoot ()
317+ );
318+ $ operation = new SearchBinaryOperator (
319+ ISearchBinaryOperator::OPERATOR_AND ,
320+ [new SearchBinaryOperator (ISearchBinaryOperator::OPERATOR_OR , [$ prefixFilter , $ rootFilter ]) , $ query ->getSearchOperation ()]
321+ );
322+ $ simpleQuery = new SearchQuery ($ operation , 0 , 0 , $ query ->getOrder (), $ query ->getUser ());
242323 $ results = $ this ->getCache ()->searchQuery ($ simpleQuery );
243324 $ results = $ this ->formatSearchResults ($ results );
244325
0 commit comments