|
10 | 10 |
|
11 | 11 | use OC\FilesMetadata\FilesMetadataManager; |
12 | 12 | use OC\SystemConfig; |
| 13 | +use OCP\DB\Exception; |
13 | 14 | use OCP\DB\QueryBuilder\IQueryBuilder; |
14 | 15 | use OCP\Files\Cache\IFileAccess; |
15 | 16 | use OCP\Files\IMimeTypeLoader; |
@@ -94,4 +95,128 @@ public function getByFileIdsInStorage(array $fileIds, int $storageId): array { |
94 | 95 | $rows = $query->executeQuery()->fetchAll(); |
95 | 96 | return $this->rowsToEntries($rows); |
96 | 97 | } |
| 98 | + |
| 99 | + public function getByAncestorInStorage(int $storageId, int $folderId, int $fileIdCursor = 0, int $maxResults = 100, array $mimeTypeIds = [], bool $endToEndEncrypted = true, bool $serverSideEncrypted = true): \Generator { |
| 100 | + $qb = $this->getQuery(); |
| 101 | + $qb->select('path') |
| 102 | + ->from('filecache') |
| 103 | + ->where($qb->expr()->eq('fileid', $qb->createNamedParameter($folderId, IQueryBuilder::PARAM_INT))); |
| 104 | + $result = $qb->executeQuery(); |
| 105 | + /** @var array{path:string}|false $root */ |
| 106 | + $root = $result->fetch(); |
| 107 | + $result->closeCursor(); |
| 108 | + |
| 109 | + if ($root === false) { |
| 110 | + throw new Exception('Could not fetch storage root'); |
| 111 | + } |
| 112 | + |
| 113 | + $qb = $this->getQuery(); |
| 114 | + |
| 115 | + $path = $root['path'] === '' ? '' : $root['path'] . '/'; |
| 116 | + |
| 117 | + $qb->selectDistinct('*') |
| 118 | + ->from('filecache', 'f') |
| 119 | + ->where($qb->expr()->like('f.path', $qb->createNamedParameter($this->connection->escapeLikeParameter($path) . '%'))) |
| 120 | + ->andWhere($qb->expr()->eq('f.storage', $qb->createNamedParameter($storageId))) |
| 121 | + ->andWhere($qb->expr()->gt('f.fileid', $qb->createNamedParameter($fileIdCursor, IQueryBuilder::PARAM_INT))); |
| 122 | + |
| 123 | + if (!$endToEndEncrypted) { |
| 124 | + // End to end encrypted files are descendants of a folder with encrypted=1 |
| 125 | + // Use a subquery to check the `encrypted` status of the parent folder |
| 126 | + $subQuery = $this->getQuery()->select('p.encrypted') |
| 127 | + ->from('filecache', 'p') |
| 128 | + ->andWhere($qb->expr()->eq('p.fileid', 'f.parent')) |
| 129 | + ->getSQL(); |
| 130 | + |
| 131 | + $qb->andWhere( |
| 132 | + $qb->expr()->eq($qb->createFunction(sprintf('(%s)', $subQuery)), $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)) |
| 133 | + ); |
| 134 | + } |
| 135 | + |
| 136 | + if (!$serverSideEncrypted) { |
| 137 | + // Server side encrypted files have encrypted=1 directly |
| 138 | + $qb->andWhere($qb->expr()->eq('f.encrypted', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT))); |
| 139 | + } |
| 140 | + |
| 141 | + if (count($mimeTypeIds) > 0) { |
| 142 | + $qb->andWhere($qb->expr()->in('f.mimetype', $qb->createNamedParameter($mimeTypeIds, IQueryBuilder::PARAM_INT_ARRAY))); |
| 143 | + } |
| 144 | + |
| 145 | + if ($maxResults !== 0) { |
| 146 | + $qb->setMaxResults($maxResults); |
| 147 | + } |
| 148 | + $qb->orderBy('f.fileid', 'ASC'); |
| 149 | + $files = $qb->executeQuery(); |
| 150 | + |
| 151 | + while ( |
| 152 | + /** @var array */ |
| 153 | + $row = $files->fetch() |
| 154 | + ) { |
| 155 | + yield Cache::cacheEntryFromData($row, $this->mimeTypeLoader); |
| 156 | + } |
| 157 | + |
| 158 | + $files->closeCursor(); |
| 159 | + } |
| 160 | + |
| 161 | + public function getDistinctMounts(array $mountProviders = [], bool $onlyUserFilesMounts = true): \Generator { |
| 162 | + $qb = $this->connection->getQueryBuilder(); |
| 163 | + $qb->selectDistinct(['root_id', 'storage_id', 'mount_provider_class']) |
| 164 | + ->from('mounts'); |
| 165 | + if ($onlyUserFilesMounts) { |
| 166 | + $qb->andWhere( |
| 167 | + $qb->expr()->orX( |
| 168 | + $qb->expr()->like('mount_point', $qb->createNamedParameter('/%/files/%')), |
| 169 | + $qb->expr()->in('mount_provider_class', $qb->createNamedParameter([ |
| 170 | + \OC\Files\Mount\LocalHomeMountProvider::class, |
| 171 | + \OC\Files\Mount\ObjectHomeMountProvider::class, |
| 172 | + ], IQueryBuilder::PARAM_STR_ARRAY)) |
| 173 | + ) |
| 174 | + ); |
| 175 | + } |
| 176 | + if (count($mountProviders) > 0) { |
| 177 | + $qb->andWhere($qb->expr()->in('mount_provider_class', $qb->createNamedParameter($mountProviders, IQueryBuilder::PARAM_STR_ARRAY))); |
| 178 | + } |
| 179 | + $qb->orderBy('root_id', 'ASC'); |
| 180 | + $result = $qb->executeQuery(); |
| 181 | + |
| 182 | + while ( |
| 183 | + /** @var array{storage_id:int, root_id:int,mount_provider_class:string} $row */ |
| 184 | + $row = $result->fetch() |
| 185 | + ) { |
| 186 | + $storageId = (int)$row['storage_id']; |
| 187 | + $rootId = (int)$row['root_id']; |
| 188 | + $overrideRoot = $rootId; |
| 189 | + // LocalHomeMountProvider is the default provider for user home directories |
| 190 | + // ObjectHomeMountProvider is the home directory provider for when S3 primary storage is used |
| 191 | + if ($onlyUserFilesMounts && in_array($row['mount_provider_class'], [ |
| 192 | + \OC\Files\Mount\LocalHomeMountProvider::class, |
| 193 | + \OC\Files\Mount\ObjectHomeMountProvider::class, |
| 194 | + ], true)) { |
| 195 | + // Only crawl files, not cache or trashbin |
| 196 | + $qb = $this->getQuery(); |
| 197 | + try { |
| 198 | + $qb->select('fileid') |
| 199 | + ->from('filecache') |
| 200 | + ->where($qb->expr()->eq('storage', $qb->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))) |
| 201 | + ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($rootId, IQueryBuilder::PARAM_INT))) |
| 202 | + ->andWhere($qb->expr()->eq('path', $qb->createNamedParameter('files'))); |
| 203 | + /** @var array|false $root */ |
| 204 | + $root = $qb->executeQuery()->fetch(); |
| 205 | + if ($root !== false) { |
| 206 | + $overrideRoot = (int)$root['fileid']; |
| 207 | + } |
| 208 | + } catch (Exception $e) { |
| 209 | + $this->logger->error('Could not fetch home storage files root for storage ' . $storageId, ['exception' => $e]); |
| 210 | + continue; |
| 211 | + } |
| 212 | + } |
| 213 | + // Reference to root_id is still necessary even if we have the overridden_root_id, because storage_id and root_id uniquely identify a mount |
| 214 | + yield [ |
| 215 | + 'storage_id' => $storageId, |
| 216 | + 'root_id' => $rootId, |
| 217 | + 'overridden_root' => $overrideRoot, |
| 218 | + ]; |
| 219 | + } |
| 220 | + $result->closeCursor(); |
| 221 | + } |
97 | 222 | } |
0 commit comments