2929namespace OC \Files \Cache \Wrapper ;
3030
3131use OC \Files \Cache \Cache ;
32+ use OC \Files \Search \SearchBinaryOperator ;
33+ use OC \Files \Search \SearchComparison ;
3234use OC \Files \Search \SearchQuery ;
35+ use OCP \DB \QueryBuilder \IQueryBuilder ;
3336use OCP \Files \Cache \ICacheEntry ;
37+ use OCP \Files \Search \ISearchBinaryOperator ;
38+ use OCP \Files \Search \ISearchComparison ;
3439use OCP \Files \Search \ISearchQuery ;
3540
3641/**
@@ -41,6 +46,7 @@ class CacheJail extends CacheWrapper {
4146 * @var string
4247 */
4348 protected $ root ;
49+ protected $ unjailedRoot ;
4450
4551 /**
4652 * @param \OCP\Files\Cache\ICache $cache
@@ -49,12 +55,29 @@ class CacheJail extends CacheWrapper {
4955 public function __construct ($ cache , $ root ) {
5056 parent ::__construct ($ cache );
5157 $ this ->root = $ root ;
58+ $ this ->connection = \OC ::$ server ->getDatabaseConnection ();
59+ $ this ->mimetypeLoader = \OC ::$ server ->getMimeTypeLoader ();
60+
61+ if ($ cache instanceof CacheJail) {
62+ $ this ->unjailedRoot = $ cache ->getSourcePath ($ root );
63+ } else {
64+ $ this ->unjailedRoot = $ root ;
65+ }
5266 }
5367
5468 protected function getRoot () {
5569 return $ this ->root ;
5670 }
5771
72+ /**
73+ * Get the root path with any nested jails resolved
74+ *
75+ * @return string
76+ */
77+ protected function getGetUnjailedRoot () {
78+ return $ this ->unjailedRoot ;
79+ }
80+
5881 protected function getSourcePath ($ path ) {
5982 if ($ path === '' ) {
6083 return $ this ->getRoot ();
@@ -65,16 +88,20 @@ protected function getSourcePath($path) {
6588
6689 /**
6790 * @param string $path
91+ * @param null|string $root
6892 * @return null|string the jailed path or null if the path is outside the jail
6993 */
70- protected function getJailedPath ($ path ) {
71- if ($ this ->getRoot () === '' ) {
94+ protected function getJailedPath (string $ path , string $ root = null ) {
95+ if ($ root === null ) {
96+ $ root = $ this ->getRoot ();
97+ }
98+ if ($ root === '' ) {
7299 return $ path ;
73100 }
74- $ rootLength = strlen ($ this -> getRoot () ) + 1 ;
75- if ($ path === $ this -> getRoot () ) {
101+ $ rootLength = strlen ($ root ) + 1 ;
102+ if ($ path === $ root ) {
76103 return '' ;
77- } elseif (substr ($ path , 0 , $ rootLength ) === $ this -> getRoot () . '/ ' ) {
104+ } elseif (substr ($ path , 0 , $ rootLength ) === $ root . '/ ' ) {
78105 return substr ($ path , $ rootLength );
79106 } else {
80107 return null ;
@@ -92,11 +119,6 @@ protected function formatCacheEntry($entry) {
92119 return $ entry ;
93120 }
94121
95- protected function filterCacheEntry ($ entry ) {
96- $ rootLength = strlen ($ this ->getRoot ()) + 1 ;
97- return $ rootLength === 1 || ($ entry ['path ' ] === $ this ->getRoot ()) || (substr ($ entry ['path ' ], 0 , $ rootLength ) === $ this ->getRoot () . '/ ' );
98- }
99-
100122 /**
101123 * get the stored metadata of a file or folder
102124 *
@@ -209,9 +231,10 @@ public function getStatus($file) {
209231 }
210232
211233 private function formatSearchResults ($ results ) {
212- $ results = array_filter ($ results , [$ this , 'filterCacheEntry ' ]);
213- $ results = array_values ($ results );
214- return array_map ([$ this , 'formatCacheEntry ' ], $ results );
234+ return array_map (function ($ entry ) {
235+ $ entry ['path ' ] = $ this ->getJailedPath ($ entry ['path ' ], $ this ->getGetUnjailedRoot ());
236+ return $ entry ;
237+ }, $ results );
215238 }
216239
217240 /**
@@ -221,7 +244,29 @@ private function formatSearchResults($results) {
221244 * @return array an array of file data
222245 */
223246 public function search ($ pattern ) {
224- $ results = $ this ->getCache ()->search ($ pattern );
247+ // normalize pattern
248+ $ pattern = $ this ->normalize ($ pattern );
249+
250+ if ($ pattern === '%% ' ) {
251+ return [];
252+ }
253+
254+ $ query = $ this ->getQueryBuilder ();
255+ $ query ->selectFileCache ()
256+ ->whereStorageId ()
257+ ->andWhere ($ query ->expr ()->orX (
258+ $ query ->expr ()->like ('path ' , $ query ->createNamedParameter ($ this ->getGetUnjailedRoot () . '/% ' )),
259+ $ query ->expr ()->eq ('path_hash ' , $ query ->createNamedParameter (md5 ($ this ->getGetUnjailedRoot ()))),
260+ ))
261+ ->andWhere ($ query ->expr ()->iLike ('name ' , $ query ->createNamedParameter ($ pattern )));
262+
263+ $ result = $ query ->execute ();
264+ $ files = $ result ->fetchAll ();
265+ $ result ->closeCursor ();
266+
267+ $ results = array_map (function (array $ data ) {
268+ return self ::cacheEntryFromData ($ data , $ this ->mimetypeLoader );
269+ }, $ files );
225270 return $ this ->formatSearchResults ($ results );
226271 }
227272
@@ -232,12 +277,48 @@ public function search($pattern) {
232277 * @return array
233278 */
234279 public function searchByMime ($ mimetype ) {
235- $ results = $ this ->getCache ()->searchByMime ($ mimetype );
280+ $ mimeId = $ this ->mimetypeLoader ->getId ($ mimetype );
281+
282+ $ query = $ this ->getQueryBuilder ();
283+ $ query ->selectFileCache ()
284+ ->whereStorageId ()
285+ ->andWhere ($ query ->expr ()->orX (
286+ $ query ->expr ()->like ('path ' , $ query ->createNamedParameter ($ this ->getGetUnjailedRoot () . '/% ' )),
287+ $ query ->expr ()->eq ('path_hash ' , $ query ->createNamedParameter (md5 ($ this ->getGetUnjailedRoot ()))),
288+ ));
289+
290+ if (strpos ($ mimetype , '/ ' )) {
291+ $ query ->andWhere ($ query ->expr ()->eq ('mimetype ' , $ query ->createNamedParameter ($ mimeId , IQueryBuilder::PARAM_INT )));
292+ } else {
293+ $ query ->andWhere ($ query ->expr ()->eq ('mimepart ' , $ query ->createNamedParameter ($ mimeId , IQueryBuilder::PARAM_INT )));
294+ }
295+
296+ $ result = $ query ->execute ();
297+ $ files = $ result ->fetchAll ();
298+ $ result ->closeCursor ();
299+
300+ $ results = array_map (function (array $ data ) {
301+ return self ::cacheEntryFromData ($ data , $ this ->mimetypeLoader );
302+ }, $ files );
236303 return $ this ->formatSearchResults ($ results );
237304 }
238305
239306 public function searchQuery (ISearchQuery $ query ) {
240- $ simpleQuery = new SearchQuery ($ query ->getSearchOperation (), 0 , 0 , $ query ->getOrder (), $ query ->getUser ());
307+ $ prefixFilter = new SearchComparison (
308+ ISearchComparison::COMPARE_LIKE ,
309+ 'path ' ,
310+ $ this ->getGetUnjailedRoot () . '/% '
311+ );
312+ $ rootFilter = new SearchComparison (
313+ ISearchComparison::COMPARE_EQUAL ,
314+ 'path ' ,
315+ $ this ->getGetUnjailedRoot ()
316+ );
317+ $ operation = new SearchBinaryOperator (
318+ ISearchBinaryOperator::OPERATOR_AND ,
319+ [new SearchBinaryOperator (ISearchBinaryOperator::OPERATOR_OR , [$ prefixFilter , $ rootFilter ]) , $ query ->getSearchOperation ()]
320+ );
321+ $ simpleQuery = new SearchQuery ($ operation , 0 , 0 , $ query ->getOrder (), $ query ->getUser ());
241322 $ results = $ this ->getCache ()->searchQuery ($ simpleQuery );
242323 $ results = $ this ->formatSearchResults ($ results );
243324
0 commit comments