Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/files_sharing/lib/SharedStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -505,4 +505,9 @@ public function file_put_contents($path, $data) {
public function setMountOptions(array $options) {
$this->mountOptions = $options;
}

public function getUnjailedPath($path) {
$this->init();
return parent::getUnjailedPath($path);
}
}
57 changes: 51 additions & 6 deletions lib/private/Files/Node/Folder.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
namespace OC\Files\Node;

use OC\DB\QueryBuilder\Literal;
use OC\Files\Storage\Wrapper\Jail;
use OCA\Files_Sharing\SharedStorage;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Config\ICachedMountInfo;
Expand Down Expand Up @@ -438,13 +439,33 @@ public function getRecent($limit, $offset = 0) {
$mountMap = array_combine($storageIds, $mounts);
$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);

/*
* Construct an array of the storage id with their prefix path
* This helps us to filter in the final query
*/
$filters = array_map(function (IMountPoint $mount) {
$storage = $mount->getStorage();

$storageId = $storage->getCache()->getNumericStorageId();
$prefix = '';

if ($storage->instanceOfStorage(Jail::class)) {
$prefix = $storage->getUnJailedPath('');
}

return [
'storageId' => $storageId,
'pathPrefix' => $prefix,
];
}, $mounts);

// Search in batches of 500 entries
$searchLimit = 500;
$results = [];
$searchResultCount = 0;
$count = 0;
do {
$searchResult = $this->recentSearch($searchLimit, $offset, $storageIds, $folderMimetype);
$searchResult = $this->recentSearch($searchLimit, $offset, $folderMimetype, $filters);

// Exit condition if there are no more results
if (count($searchResult) === 0) {
Expand All @@ -466,13 +487,36 @@ public function getRecent($limit, $offset = 0) {
return array_slice($results, 0, $limit);
}

private function recentSearch($limit, $offset, $storageIds, $folderMimetype) {
$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
private function recentSearch($limit, $offset, $folderMimetype, $filters) {
$dbconn = \OC::$server->getDatabaseConnection();
$builder = $dbconn->getQueryBuilder();
$query = $builder
->select('f.*')
->from('filecache', 'f')
->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
->andWhere($builder->expr()->orX(
->from('filecache', 'f');

/*
* Here is where we construct the filtering.
* Note that this is expensive filtering as it is a lot of like queries.
* However the alternative is we do this filtering and parsing later in php with the risk of looping endlessly
*/
$storageFilters = $builder->expr()->orX();
foreach ($filters as $filter) {
$storageFilter = $builder->expr()->andX(
$builder->expr()->eq('f.storage', $builder->createNamedParameter($filter['storageId']))
);

if ($filter['pathPrefix'] !== '') {
$storageFilter->add(
$builder->expr()->like('f.path', $builder->createNamedParameter($dbconn->escapeLikeParameter($filter['pathPrefix']) . '/%'))
);
}

$storageFilters->add($storageFilter);
}

$query->andWhere($storageFilters);

$query->andWhere($builder->expr()->orX(
// handle non empty folders separate
$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
$builder->expr()->eq('f.size', new Literal(0))
Expand All @@ -482,6 +526,7 @@ private function recentSearch($limit, $offset, $storageIds, $folderMimetype) {
->orderBy('f.mtime', 'DESC')
->setMaxResults($limit)
->setFirstResult($offset);

return $query->execute()->fetchAll();
}

Expand Down